diff --git a/examples/src/Jeep.obj.txt b/examples/src/Jeep.obj.txt new file mode 100644 index 0000000..6921c34 --- /dev/null +++ b/examples/src/Jeep.obj.txt @@ -0,0 +1,2213 @@ +# Blender v2.92.0 OBJ File: 'jeep.blend' +# www.blender.org +# The Jeep model is courtesy of Kolja Wilcke +mtllib jeep.mtl +o convex-base_Base +v -2.242281 -4.524718 1.272481 +v -2.242281 -4.524718 3.488908 +v -2.242281 4.246403 1.272481 +v -2.242281 3.677963 3.488908 +v 2.242281 -4.524718 1.272481 +v 2.242281 -4.524718 3.488908 +v 2.242281 4.246403 1.272481 +v 2.242281 3.677963 3.488908 +v -2.242281 4.246403 2.380695 +v 2.242281 4.246403 2.380695 +vt 0.375000 0.750000 +vt 0.625000 0.750000 +vt 0.625000 1.000000 +vt 0.375000 1.000000 +vt 0.500000 0.250000 +vt 0.625000 0.250000 +vt 0.625000 0.500000 +vt 0.500000 0.500000 +vt 0.375000 0.000000 +vt 0.625000 0.000000 +vt 0.375000 0.250000 +vt 0.125000 0.500000 +vt 0.375000 0.500000 +vt 0.125000 0.750000 +vt 0.875000 0.500000 +vt 0.875000 0.750000 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 0.8898 0.4564 +vn -1.0000 0.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 0.0000 0.0000 1.0000 +vn 0.0000 1.0000 0.0000 +vn 1.0000 0.0000 0.0000 +usemtl None +s off +f 5/1/1 6/2/1 2/3/1 1/4/1 +f 9/5/2 4/6/2 8/7/2 10/8/2 +f 1/9/3 2/10/3 4/6/3 9/5/3 3/11/3 +f 3/12/4 7/13/4 5/1/4 1/14/4 +f 8/7/5 4/15/5 2/16/5 6/2/5 +f 3/11/6 9/5/6 10/8/6 7/13/6 +f 7/13/7 10/8/7 8/7/7 6/2/7 5/1/7 +o convex-window_Window +v -2.242281 0.283938 5.497181 +v -2.242281 0.751557 3.488908 +v -2.242281 0.635509 5.497181 +v -2.242281 1.103128 3.488908 +v 2.242281 0.283938 5.497181 +v 2.242281 0.751557 3.488908 +v 2.242281 0.635509 5.497181 +v 2.242281 1.103128 3.488908 +vt 0.375000 0.000000 +vt 0.375000 0.250000 +vt 0.625000 0.250000 +vt 0.625000 0.000000 +vt 0.375000 0.500000 +vt 0.625000 0.500000 +vt 0.375000 0.750000 +vt 0.625000 0.750000 +vt 0.375000 1.000000 +vt 0.625000 1.000000 +vt 0.125000 0.500000 +vt 0.125000 0.750000 +vt 0.875000 0.750000 +vt 0.875000 0.500000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 0.9739 0.2268 +vn 1.0000 0.0000 0.0000 +vn 0.0000 -0.9739 -0.2268 +vn 0.0000 0.0000 1.0000 +vn 0.0000 0.0000 -1.0000 +usemtl None +s off +f 11/17/8 13/18/8 14/19/8 12/20/8 +f 13/18/9 17/21/9 18/22/9 14/19/9 +f 17/21/10 15/23/10 16/24/10 18/22/10 +f 15/23/11 11/25/11 12/26/11 16/24/11 +f 13/27/12 11/28/12 15/23/12 17/21/12 +f 18/22/13 16/24/13 12/29/13 14/30/13 +o front-right_Axis3d +v 1.832790 2.783146 1.139400 +v 1.932790 2.783146 1.139400 +l 19 20 +o rear-right_Axis3d +v 1.832790 -2.992498 1.139400 +v 1.932790 -2.992498 1.139400 +l 21 22 +o front-left_Axis3d +v -1.810560 2.846034 1.139400 +v -1.910560 2.846034 1.139400 +l 23 24 +o rear-left_Axis3d +v -1.810560 -2.858030 1.139400 +v -1.910560 -2.858030 1.139400 +l 25 26 +o chassis_Chassis +v 1.277467 3.619387 3.206276 +v 0.825481 3.619387 1.542987 +v 1.326676 1.110030 1.299445 +v 1.478835 1.110030 1.508627 +v 1.277467 3.619387 2.455048 +v 2.190520 1.110030 1.508627 +v 2.190520 1.110030 3.299445 +v 1.705413 3.619387 3.206276 +v 1.705413 3.619387 2.455048 +v 1.478835 -2.012901 2.363739 +v 1.478835 -2.012901 3.299445 +v 1.326676 -2.012901 1.299445 +v 2.190520 -2.012901 2.363739 +v 2.190520 -2.012901 3.299445 +v 1.478835 -4.041931 1.927432 +v 1.326676 -4.041931 1.299445 +v 2.190520 -4.041931 1.927432 +v 2.190520 -4.041931 3.299445 +v 0.655219 3.619387 1.542987 +v 1.175348 1.110030 3.299445 +v 0.811583 3.619387 3.206276 +v 0.730915 3.619387 2.240386 +v 0.664338 3.619387 3.501884 +v 0.583671 3.502560 2.240386 +v 0.523028 3.502560 1.542987 +v 0.939721 1.110030 3.595053 +v 2.190520 0.775040 1.508627 +v 1.478835 0.775040 1.508627 +v 1.326676 0.775040 1.299445 +v 1.277467 3.619387 3.097432 +v 2.190520 0.775040 3.299445 +v 1.780108 0.775040 3.299445 +v 1.835736 0.632188 5.497213 +v 2.093769 0.632188 5.472280 +v 2.093769 0.297198 5.472280 +v 1.777038 0.297198 5.497213 +v 1.478835 0.387261 1.508627 +v 1.326676 0.387261 1.299445 +v 1.824495 0.387261 2.627326 +v 1.326676 -3.388509 1.299445 +v 2.190520 0.387261 1.508627 +v 2.190520 0.387261 2.627326 +v 1.478835 -1.608775 1.508627 +v 1.326676 -1.608775 1.299445 +v 2.190520 -3.388509 3.299445 +v 2.190520 -3.388510 2.363739 +v 1.824495 -1.608775 2.627326 +v 1.478835 -3.388510 2.363739 +v 2.190520 -1.608775 1.508627 +v 2.190520 -1.608775 2.627326 +v 2.190520 -3.684435 1.927432 +v 1.478835 -3.684435 1.927432 +v 2.190520 -3.684435 3.299445 +v 1.478835 -3.684435 3.299445 +v 1.326676 -3.684435 1.299445 +v 1.478835 -2.012901 2.618106 +v 1.824495 -1.608775 1.835406 +v 1.824495 0.775040 1.835406 +v 1.824495 0.387261 1.835406 +v 1.208939 1.579852 1.299445 +v 1.347691 1.579852 2.331105 +v 1.996666 1.579852 3.299445 +v 1.996666 1.579852 2.331105 +v 1.070946 1.579852 3.299445 +v 0.856081 1.579852 3.595053 +v 2.190520 0.370200 5.170483 +v 2.190520 0.705190 5.170483 +v 1.780108 0.370200 5.170483 +v 1.835736 0.705190 5.170483 +v 0.939721 1.030688 3.922539 +v 2.190520 1.030688 3.922539 +v 1.835736 1.030688 3.922539 +v 2.190520 0.695697 3.922539 +v 1.780108 0.695697 3.922539 +v 2.190520 1.110030 2.871010 +v 1.705413 3.619387 3.097432 +v 1.478835 -3.388510 2.618106 +v 0.730915 3.619387 3.097432 +v 0.583671 3.502560 3.322319 +v 2.190520 0.775040 2.871010 +v 1.996666 1.579852 3.067780 +v 1.286705 3.351099 2.438745 +v 1.743726 3.351099 3.299445 +v 1.743726 3.351099 2.438745 +v 0.875922 3.351099 1.299445 +v 0.695375 3.351099 1.299445 +v 0.856311 3.351099 3.299445 +v 0.700172 3.351099 3.595053 +v 0.555198 3.351099 1.299445 +v 1.743726 3.351099 3.093531 +v -1.277467 3.619387 3.206276 +v -0.825481 3.619387 1.542987 +v -1.326676 1.110030 1.299445 +v -1.478835 1.110030 1.508627 +v -1.277467 3.619387 2.455048 +v -2.190520 1.110030 1.508627 +v -2.190520 1.110030 3.299445 +v -1.705413 3.619387 3.206276 +v -1.705413 3.619387 2.455048 +v -1.478835 -2.012901 2.363739 +v -1.478835 -2.012901 3.299445 +v -1.326676 -2.012901 1.299445 +v -2.190520 -2.012901 2.363739 +v -2.190520 -2.012901 3.299445 +v -1.478835 -4.041931 1.927432 +v -1.326676 -4.041931 1.299445 +v -2.190520 -4.041931 1.927432 +v -2.190520 -4.041931 3.299445 +v -0.655219 3.619387 1.542987 +v -1.175348 1.110030 3.299445 +v -0.811583 3.619387 3.206276 +v -0.730915 3.619387 2.240386 +v -0.664338 3.619387 3.501884 +v -0.583671 3.502560 2.240386 +v -0.523028 3.502560 1.542987 +v -0.939721 1.110030 3.595053 +v -2.190520 0.775040 1.508627 +v -1.478835 0.775040 1.508627 +v -1.326676 0.775040 1.299445 +v -1.277467 3.619387 3.097432 +v -2.190520 0.775040 3.299445 +v -1.780108 0.775040 3.299445 +v -1.835736 0.632188 5.497213 +v -2.093769 0.632188 5.472280 +v -2.093769 0.297198 5.472280 +v -1.777038 0.297198 5.497213 +v -1.478835 0.387261 1.508627 +v -1.326676 0.387261 1.299445 +v -1.824495 0.387261 2.627326 +v -1.326676 -3.388509 1.299445 +v -2.190520 0.387261 1.508627 +v -2.190520 0.387261 2.627326 +v -1.478835 -1.608775 1.508627 +v -1.326676 -1.608775 1.299445 +v -2.190520 -3.388509 3.299445 +v -2.190520 -3.388510 2.363739 +v -1.824495 -1.608775 2.627326 +v -1.478835 -3.388510 2.363739 +v -2.190520 -1.608775 1.508627 +v -2.190520 -1.608775 2.627326 +v -2.190520 -3.684435 1.927432 +v -1.478835 -3.684435 1.927432 +v -2.190520 -3.684435 3.299445 +v -1.478835 -3.684435 3.299445 +v -1.326676 -3.684435 1.299445 +v -1.478835 -2.012901 2.618106 +v -1.824495 -1.608775 1.835406 +v -1.824495 0.775040 1.835406 +v -1.824495 0.387261 1.835406 +v -1.208939 1.579852 1.299445 +v -1.347691 1.579852 2.331105 +v -1.996666 1.579852 3.299445 +v -1.996666 1.579852 2.331105 +v -1.070946 1.579852 3.299445 +v -0.856081 1.579852 3.595053 +v -2.190520 0.370200 5.170483 +v -2.190520 0.705190 5.170483 +v -1.780108 0.370200 5.170483 +v -1.835736 0.705190 5.170483 +v -0.939721 1.030688 3.922539 +v -2.190520 1.030688 3.922539 +v -1.835736 1.030688 3.922539 +v -2.190520 0.695697 3.922539 +v -1.780108 0.695697 3.922539 +v -2.190520 1.110030 2.871010 +v -1.705413 3.619387 3.097432 +v -1.478835 -3.388510 2.618106 +v -0.730915 3.619387 3.097432 +v -0.583671 3.502560 3.322319 +v -1.996666 1.579852 3.067780 +v -1.286705 3.351099 2.438745 +v -1.743726 3.351099 3.299445 +v -1.743726 3.351099 2.438745 +v -0.875922 3.351099 1.299445 +v -0.695375 3.351099 1.299445 +v -0.856311 3.351099 3.299445 +v -0.700172 3.351099 3.595053 +v -0.555198 3.351099 1.299445 +v -1.743726 3.351099 3.093531 +vt 0.706042 0.690913 +vt 0.706042 0.702725 +vt 0.707871 0.702725 +vt 0.707871 0.690913 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.690094 0.653570 +vt 0.682588 0.653570 +vt 0.682588 0.653570 +vt 0.690094 0.653570 +vt 0.949194 0.689365 +vt 0.972131 0.689365 +vt 0.972131 0.689365 +vt 0.949194 0.689365 +vt 0.657790 0.689124 +vt 0.657790 0.689124 +vt 0.657790 0.690913 +vt 0.657790 0.690913 +vt 0.672317 0.669558 +vt 0.672317 0.671347 +vt 0.682588 0.671347 +vt 0.682588 0.669558 +vt 0.958083 0.666065 +vt 0.958083 0.666065 +vt 0.928493 0.666065 +vt 0.928493 0.666065 +vt 0.688298 0.669558 +vt 0.688298 0.671347 +vt 0.690094 0.671347 +vt 0.690094 0.669558 +vt 0.187708 0.674483 +vt 0.187708 0.674483 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.688298 0.671347 +vt 0.682588 0.671347 +vt 0.690094 0.653570 +vt 0.682588 0.653570 +vt 0.682588 0.653570 +vt 0.690094 0.653570 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.704621 0.706901 +vt 0.706042 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.704621 0.706901 +vt 0.931231 0.723642 +vt 0.931231 0.723642 +vt 0.931231 0.717873 +vt 0.931231 0.688177 +vt 0.931231 0.688177 +vt 0.931231 0.717873 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.713779 0.700933 +vt 0.713779 0.700933 +vt 0.711675 0.700933 +vt 0.711675 0.700933 +vt 0.311695 0.691093 +vt 0.311695 0.691093 +vt 0.311695 0.691093 +vt 0.311695 0.691093 +vt 0.672317 0.673176 +vt 0.682588 0.673176 +vt 0.688298 0.673176 +vt 0.690094 0.673176 +vt 0.690094 0.671347 +vt 0.704621 0.702725 +vt 0.704621 0.706901 +vt 0.706042 0.706901 +vt 0.704621 0.690913 +vt 0.704621 0.690913 +vt 0.704621 0.702725 +vt 0.907932 0.683659 +vt 0.907932 0.689365 +vt 0.949194 0.683659 +vt 0.688298 0.674597 +vt 0.690094 0.674597 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707652 0.706512 +vt 0.707871 0.706901 +vt 0.690094 0.653570 +vt 0.690094 0.653570 +vt 0.690094 0.653570 +vt 0.690094 0.653570 +vt 0.690094 0.653570 +vt 0.682588 0.653570 +vt 0.682588 0.653570 +vt 0.690094 0.653570 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.958083 0.666065 +vt 0.958083 0.666065 +vt 0.928493 0.666065 +vt 0.928493 0.666065 +vt 0.690094 0.653570 +vt 0.690094 0.653570 +vt 0.698661 0.681849 +vt 0.678901 0.681849 +vt 0.678901 0.687284 +vt 0.698661 0.687284 +vt 0.704621 0.706901 +vt 0.682588 0.653570 +vt 0.682588 0.657746 +vt 0.688298 0.657746 +vt 0.688298 0.653570 +vt 0.673772 0.681848 +vt 0.674144 0.685802 +vt 0.958083 0.666065 +vt 0.928493 0.666065 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.688298 0.653570 +vt 0.682588 0.653570 +vt 0.690094 0.654414 +vt 0.690094 0.653570 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.958083 0.666065 +vt 0.928493 0.666065 +vt 0.958083 0.666065 +vt 0.928493 0.666065 +vt 0.337939 0.694193 +vt 0.337939 0.694193 +vt 0.337939 0.694193 +vt 0.337939 0.694193 +vt 0.311695 0.691093 +vt 0.311695 0.691093 +vt 0.311695 0.691093 +vt 0.311695 0.691093 +vt 0.704621 0.689124 +vt 0.704621 0.689124 +vt 0.187708 0.710090 +vt 0.187708 0.710090 +vt 0.690094 0.656901 +vt 0.928493 0.678094 +vt 0.958083 0.678094 +vt 0.706042 0.690913 +vt 0.707871 0.690913 +vt 0.707871 0.702725 +vt 0.706042 0.702725 +vt 0.682034 0.679580 +vt 0.650246 0.679580 +vt 0.652330 0.687687 +vt 0.684118 0.687687 +vt 0.690094 0.653570 +vt 0.690094 0.653570 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.972131 0.683659 +vt 0.682588 0.669558 +vt 0.907932 0.689365 +vt 0.930620 0.331406 +vt 0.930620 0.331406 +vt 0.930620 0.331406 +vt 0.930620 0.331406 +vt 0.930620 0.331406 +vt 0.930620 0.331406 +vt 0.930620 0.331406 +vt 0.930620 0.331406 +vt 0.930620 0.331406 +vt 0.930620 0.321289 +vt 0.930620 0.292673 +vt 0.935053 0.292673 +vt 0.938494 0.292673 +vt 0.938494 0.292673 +vt 0.935053 0.292673 +vt 0.930620 0.292673 +vt 0.930620 0.321289 +vt 0.930620 0.331406 +vt 0.930620 0.331406 +vt 0.930620 0.331406 +vt 0.930620 0.331406 +vt 0.930620 0.331406 +vt 0.930620 0.331406 +vt 0.930620 0.331406 +vt 0.654540 0.689124 +vt 0.654540 0.690913 +vt 0.656369 0.690913 +vt 0.656369 0.689124 +vt 0.706042 0.689124 +vt 0.688298 0.674597 +vt 0.690094 0.674597 +vt 0.928493 0.712121 +vt 0.958083 0.712121 +vt 0.311695 0.691093 +vt 0.311695 0.691093 +vt 0.724763 0.687992 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.724763 0.687992 +vt 0.000000 0.000000 +vt 0.000000 0.000000 +vt 0.000000 0.000000 +vt 0.000000 0.000000 +vt 0.690094 0.724678 +vt 0.682588 0.724678 +vt 0.682588 0.724678 +vt 0.672317 0.724678 +vt 0.672317 0.724678 +vt 0.682588 0.724678 +vt 0.682588 0.724678 +vt 0.690094 0.724678 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.707871 0.689124 +vt 0.707871 0.689124 +vt 0.672317 0.669558 +vt 0.682588 0.669558 +vt 0.682588 0.671347 +vt 0.672317 0.671347 +vt 0.958083 0.666065 +vt 0.928493 0.666065 +vt 0.928493 0.666065 +vt 0.958083 0.666065 +vt 0.688298 0.669558 +vt 0.690094 0.669558 +vt 0.690094 0.671347 +vt 0.688298 0.671347 +vt 0.187708 0.674483 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.187708 0.674483 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.688298 0.671347 +vt 0.682588 0.671347 +vt 0.690094 0.653570 +vt 0.682588 0.653570 +vt 0.682588 0.653570 +vt 0.690094 0.653570 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.713779 0.700933 +vt 0.711675 0.700933 +vt 0.711675 0.700933 +vt 0.713779 0.700933 +vt 0.311695 0.691093 +vt 0.311695 0.691093 +vt 0.311695 0.691093 +vt 0.311695 0.691093 +vt 0.682588 0.673176 +vt 0.672317 0.673176 +vt 0.690094 0.671347 +vt 0.690094 0.673176 +vt 0.688298 0.673176 +vt 0.907932 0.683659 +vt 0.949194 0.683659 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707652 0.706512 +vt 0.707871 0.706901 +vt 0.690094 0.653570 +vt 0.690094 0.653570 +vt 0.690094 0.653570 +vt 0.690094 0.653570 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.958083 0.666065 +vt 0.928493 0.666065 +vt 0.928493 0.666065 +vt 0.958083 0.666065 +vt 0.690094 0.653570 +vt 0.690094 0.653570 +vt 0.698661 0.681849 +vt 0.698661 0.687284 +vt 0.678901 0.687284 +vt 0.678901 0.681849 +vt 0.682588 0.653570 +vt 0.688298 0.653570 +vt 0.688298 0.657746 +vt 0.682588 0.657746 +vt 0.674144 0.685802 +vt 0.673772 0.681848 +vt 0.698936 0.727990 +vt 0.698936 0.727990 +vt 0.698936 0.727990 +vt 0.698936 0.727990 +vt 0.928493 0.666065 +vt 0.958083 0.666065 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.707871 0.706901 +vt 0.682588 0.653570 +vt 0.682588 0.653570 +vt 0.690094 0.653570 +vt 0.690094 0.653570 +vt 0.682588 0.653570 +vt 0.690094 0.653570 +vt 0.690094 0.654414 +vt 0.187708 0.661895 +vt 0.187708 0.661895 +vt 0.928493 0.666065 +vt 0.958083 0.666065 +vt 0.928493 0.666065 +vt 0.958083 0.666065 +vt 0.311695 0.691093 +vt 0.311695 0.691093 +vt 0.311695 0.691093 +vt 0.311695 0.691093 +vt 0.187708 0.710090 +vt 0.187708 0.710090 +vt 0.690094 0.656901 +vt 0.958083 0.678094 +vt 0.928493 0.678094 +vt 0.707871 0.689124 +vt 0.707871 0.689124 +vt 0.706042 0.689124 +vt 0.682034 0.679580 +vt 0.684118 0.687687 +vt 0.652330 0.687687 +vt 0.650246 0.679580 +vt 0.690094 0.653570 +vt 0.690094 0.653570 +vt 0.972131 0.683659 +vt 0.682588 0.669558 +vt 0.654540 0.689124 +vt 0.656369 0.689124 +vt 0.656369 0.690913 +vt 0.654540 0.690913 +vt 0.958083 0.712121 +vt 0.928493 0.712121 +vt 0.311695 0.691093 +vt 0.311695 0.691093 +vt 0.000000 0.000000 +vt 0.000000 0.000000 +vt 0.690094 0.653570 +vt 0.682588 0.653570 +vt 0.682588 0.653570 +vt 0.690094 0.653570 +vt 0.707871 0.706901 +vt 0.936374 0.675071 +vt 0.936374 0.675071 +vn 0.0000 0.0000 1.0000 +vn 0.0000 0.0000 -1.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 1.0000 0.0000 +vn 0.0000 0.8492 -0.5281 +vn 0.8853 0.2788 -0.3723 +vn 0.9445 -0.2388 -0.2257 +vn 0.9900 0.1414 0.0000 +vn 0.0000 0.8683 -0.4960 +vn 0.0000 -0.9041 -0.4273 +vn -0.0156 0.9911 0.1321 +vn 0.0000 0.8570 0.5153 +vn 0.9719 0.0000 -0.2355 +vn -0.9990 -0.0401 -0.0197 +vn 0.7855 0.1572 0.5985 +vn -0.6402 0.7656 0.0626 +vn -0.4867 0.8699 -0.0801 +vn -0.0078 -0.9738 -0.2274 +vn 0.9523 0.0000 0.3053 +vn -1.0000 0.0000 0.0000 +vn 0.8087 0.0000 -0.5882 +vn 0.0864 -0.0076 0.9962 +vn 0.0000 0.9676 0.2524 +vn 0.0000 0.9719 0.2355 +vn 0.9244 0.3814 0.0000 +vn 0.0093 0.9737 0.2276 +vn 0.9899 0.0000 -0.1415 +vn 0.0000 -0.8662 0.4997 +vn 0.9759 0.1294 -0.1755 +vn 0.0000 0.8276 -0.5613 +vn 0.0000 -1.0000 0.0000 +vn -0.7599 0.6500 0.0000 +vn 0.0000 0.3281 0.9447 +vn 0.8437 0.0883 0.5295 +vn 0.0000 0.0607 -0.9982 +vn 0.8853 0.4162 -0.2076 +vn -0.9856 0.1637 0.0427 +vn 0.0000 -0.9676 -0.2524 +vn 0.0156 0.9911 0.1321 +vn -0.6215 0.7834 0.0000 +vn -0.0000 0.6721 -0.7404 +vn 0.8540 0.2804 0.4382 +vn 0.0000 0.8382 -0.5453 +vn -0.3003 0.7001 -0.6479 +vn 0.9630 0.1145 -0.2438 +vn 0.0000 -0.9920 -0.1263 +vn 0.0000 0.9172 0.3984 +vn -0.8853 0.2788 -0.3723 +vn -0.9445 -0.2388 -0.2257 +vn -0.9900 0.1414 0.0000 +vn -0.9719 0.0000 -0.2355 +vn 0.9990 -0.0401 -0.0197 +vn -0.7855 0.1572 0.5985 +vn 0.6402 0.7656 0.0626 +vn 0.4867 0.8699 -0.0801 +vn 0.0078 -0.9738 -0.2274 +vn -0.9523 0.0000 0.3053 +vn 0.0000 -0.9759 -0.2181 +vn -0.8087 0.0000 -0.5882 +vn -0.0864 -0.0076 0.9962 +vn -0.9244 0.3814 0.0000 +vn -0.0093 0.9737 0.2276 +vn 0.0000 0.9759 0.2181 +vn -0.9899 0.0000 -0.1415 +vn -0.9759 0.1294 -0.1755 +vn 0.7599 0.6500 0.0000 +vn -0.8437 0.0883 0.5295 +vn -0.8853 0.4162 -0.2076 +vn 0.9856 0.1637 0.0427 +vn 0.6215 0.7834 0.0000 +vn -0.8540 0.2804 0.4382 +vn 0.3003 0.7001 -0.6479 +vn -0.9630 0.1145 -0.2438 +vn 0.0000 0.8886 0.4588 +usemtl Material +s off +f 113/31/14 90/32/14 88/33/14 109/34/14 +f 39/35/15 72/36/15 74/37/15 36/38/15 +f 76/39/16 75/40/16 67/41/16 68/42/16 +f 140/43/17 195/44/17 105/45/17 50/46/17 +f 141/47/18 51/48/18 115/49/18 204/50/18 +f 111/51/19 28/52/19 31/53/19 108/54/19 +f 69/55/20 36/56/20 38/57/20 70/58/20 +f 116/59/21 102/60/21 34/61/21 109/62/21 +f 87/63/22 89/64/22 32/65/22 30/66/22 +f 75/67/23 39/35/23 36/38/23 69/68/23 +f 56/69/17 102/60/17 35/70/17 31/53/17 +f 71/71/16 72/72/16 39/73/16 40/74/16 +f 77/75/15 43/76/15 41/77/15 78/78/15 +f 142/79/24 136/80/24 123/81/24 187/82/24 188/83/24 186/84/24 +f 84/85/14 174/86/14 175/87/14 173/88/14 83/89/14 85/90/14 +f 73/91/25 37/92/25 40/93/25 76/94/25 +f 78/95/26 41/96/26 42/97/26 81/98/26 +f 58/99/27 84/100/27 85/101/27 65/102/27 +f 28/52/17 45/103/17 48/104/17 31/53/17 +f 56/69/17 104/105/17 47/106/17 27/107/17 +f 91/108/28 52/109/28 46/110/28 90/32/28 +f 114/111/14 203/112/14 181/113/14 91/108/14 +f 45/114/29 51/115/29 50/46/29 48/116/29 +f 104/105/30 105/117/30 49/118/30 47/106/30 +f 92/119/31 61/120/31 62/121/31 94/122/31 +f 93/123/32 60/124/32 61/125/32 92/126/32 +f 158/127/33 157/128/33 165/129/33 166/130/33 +f 32/65/15 53/131/15 54/132/15 30/66/15 +f 30/133/34 54/134/34 55/135/34 29/136/34 +f 59/137/35 62/138/35 61/125/35 60/124/35 +f 98/139/36 95/140/36 93/141/36 97/142/36 +f 52/109/37 142/79/37 186/84/37 96/143/37 +f 32/144/38 89/145/38 107/146/38 101/147/38 +f 95/140/39 59/148/39 60/149/39 93/141/39 +f 36/56/40 74/150/40 66/151/40 38/57/40 +f 58/152/41 65/153/41 68/154/41 57/155/41 +f 106/156/16 53/157/16 32/144/16 101/147/16 33/158/16 57/159/16 +f 53/131/15 67/160/15 63/161/15 54/132/15 +f 54/134/34 63/162/34 64/163/34 55/135/34 +f 65/153/14 73/91/14 76/94/14 68/154/14 +f 68/42/16 67/41/16 53/157/16 106/156/16 57/159/16 +f 67/160/15 75/67/15 69/68/15 63/161/15 +f 63/162/34 69/55/34 70/58/34 64/163/34 +f 74/150/42 78/164/42 81/165/42 66/151/42 +f 72/36/43 77/75/43 78/78/43 74/37/43 +f 84/166/44 58/167/44 148/168/44 174/169/44 +f 65/102/33 85/101/33 83/170/33 73/171/33 +f 73/171/45 83/170/45 82/172/45 37/173/45 +f 49/174/46 139/175/46 203/112/46 114/111/46 +f 114/111/47 91/108/47 90/32/47 113/31/47 +f 108/176/48 110/177/48 89/64/48 87/63/48 +f 101/147/38 107/146/38 88/178/38 33/158/38 +f 29/136/49 86/179/49 87/180/49 30/133/49 +f 202/181/14 198/182/14 178/183/14 180/184/14 +f 180/184/14 178/183/14 123/81/14 136/80/14 +f 100/185/50 94/186/50 95/187/50 98/188/50 +f 97/189/16 93/123/16 92/126/16 99/190/16 +f 99/191/51 92/119/51 94/122/51 100/192/51 +f 33/158/16 97/189/16 99/190/16 57/159/16 +f 52/109/52 96/143/52 98/193/52 97/194/52 33/195/52 46/110/52 +f 91/108/14 181/113/14 142/79/14 52/109/14 +f 48/116/53 50/46/53 105/45/53 104/196/53 +f 31/53/17 48/104/17 104/105/17 56/69/17 +f 27/107/17 34/61/17 102/60/17 56/69/17 +f 110/197/21 35/70/21 102/60/21 116/59/21 +f 141/198/17 140/43/17 50/46/17 51/115/17 +f 89/145/21 110/197/21 116/59/21 107/146/21 +f 42/199/15 132/200/15 171/201/15 156/202/15 128/203/15 160/204/15 154/205/15 145/206/15 119/207/15 176/208/15 200/209/15 201/210/15 204/211/15 115/212/15 112/213/15 111/214/15 86/215/15 29/216/15 55/217/15 64/218/15 70/219/15 38/220/15 66/221/15 81/222/15 +f 31/53/48 35/70/48 110/197/48 108/54/48 +f 28/223/54 111/224/54 112/225/54 45/226/54 +f 49/174/55 114/111/55 113/31/55 47/227/55 +f 195/228/56 139/229/56 49/118/56 105/117/56 +f 45/226/57 112/225/57 115/49/57 51/48/57 +f 107/146/21 116/59/21 109/62/21 88/178/21 +f 86/179/58 111/230/58 108/231/58 87/180/58 +f 82/172/33 103/232/33 80/233/33 37/173/33 +f 58/152/59 57/155/59 99/191/59 100/234/59 190/235/59 189/236/59 147/237/59 148/238/59 +f 170/239/60 80/240/60 103/241/60 193/242/60 +f 134/243/44 133/244/44 131/245/44 132/246/44 42/247/44 41/248/44 43/249/44 44/250/44 +f 90/32/14 46/110/14 33/195/14 88/33/14 +f 129/251/15 126/252/15 164/253/15 162/254/15 +f 113/31/46 109/34/46 34/255/46 27/256/46 47/227/46 +f 200/257/61 197/258/61 121/259/61 118/260/61 +f 159/261/62 160/262/62 128/263/62 126/264/62 +f 205/265/63 198/266/63 124/267/63 192/268/63 +f 177/269/22 120/270/22 122/271/22 179/272/22 +f 165/273/23 159/274/23 126/252/23 129/251/23 +f 146/275/17 121/259/17 125/276/17 192/268/17 +f 130/277/33 129/278/33 162/279/33 161/280/33 +f 167/281/15 168/282/15 131/283/15 133/284/15 +f 40/74/16 39/73/16 75/40/16 76/39/16 +f 134/285/14 44/286/14 79/287/14 80/288/14 170/289/14 169/290/14 +f 163/291/25 166/292/25 130/293/25 127/294/25 +f 37/92/14 80/288/14 79/287/14 71/295/14 40/93/14 +f 168/296/64 171/297/64 132/298/64 131/299/64 +f 148/300/65 155/301/65 175/302/65 174/303/65 +f 118/260/17 121/259/17 138/304/17 135/305/17 +f 146/275/17 117/306/17 137/307/17 194/308/17 +f 181/113/66 180/184/66 136/80/66 142/79/66 +f 135/309/67 138/310/67 140/43/67 141/198/67 +f 194/308/68 137/307/68 139/229/68 195/228/68 +f 182/311/69 184/312/69 152/313/69 151/314/69 +f 183/315/70 182/316/70 151/317/70 150/318/70 +f 62/121/71 152/313/71 184/312/71 94/122/71 +f 122/271/15 120/270/15 144/319/15 143/320/15 +f 120/321/72 119/322/72 145/323/72 144/324/72 +f 149/325/73 150/318/73 151/317/73 152/326/73 +f 188/327/36 187/328/36 183/329/36 185/330/36 +f 166/130/33 165/129/33 129/278/33 130/277/33 +f 122/331/74 191/332/74 196/333/74 179/334/74 +f 185/330/75 183/329/75 150/335/75 149/336/75 +f 59/148/76 95/140/76 185/330/76 149/336/76 +f 94/337/15 184/338/15 185/339/15 95/340/15 +f 126/264/77 128/263/77 156/341/77 164/342/77 +f 148/343/41 147/237/41 158/344/41 155/345/41 +f 167/346/33 133/347/33 134/348/33 169/349/33 161/280/33 162/279/33 +f 191/332/33 122/331/33 143/350/33 147/351/33 123/352/33 +f 143/320/15 144/319/15 153/353/15 157/354/15 +f 144/324/72 145/323/72 154/355/72 153/356/72 +f 155/345/14 158/344/14 166/292/14 163/291/14 +f 147/351/33 143/350/33 157/128/33 158/127/33 +f 157/354/15 153/353/15 159/274/15 165/273/15 +f 153/356/72 154/355/72 160/262/72 159/261/72 +f 164/342/78 156/341/78 171/357/78 168/358/78 +f 162/254/43 164/253/43 168/282/43 167/281/43 +f 155/301/16 163/359/16 173/360/16 175/302/16 +f 163/359/79 127/361/79 172/362/79 173/360/79 +f 203/112/80 202/181/80 180/184/80 181/113/80 +f 197/363/48 177/269/48 179/272/48 199/364/48 +f 191/332/74 123/352/74 178/365/74 196/333/74 +f 119/322/81 120/321/81 177/366/81 176/367/81 +f 117/368/46 124/369/46 198/182/46 202/181/46 137/370/46 +f 190/371/82 188/372/82 185/373/82 184/374/82 +f 187/375/33 189/376/33 182/316/33 183/315/33 +f 189/236/51 190/235/51 184/312/51 182/311/51 +f 123/352/33 147/351/33 189/376/33 187/375/33 +f 138/310/83 194/377/83 195/44/83 140/43/83 +f 121/259/17 146/275/17 194/308/17 138/304/17 +f 117/306/17 146/275/17 192/268/17 124/267/17 +f 199/378/63 205/265/63 192/268/63 125/276/63 +f 179/334/63 196/333/63 205/265/63 199/378/63 +f 121/259/48 197/258/48 199/378/48 125/276/48 +f 118/379/54 135/380/54 201/381/54 200/382/54 +f 139/175/84 137/370/84 202/181/84 203/112/84 +f 135/380/85 141/47/85 204/50/85 201/381/85 +f 196/333/63 178/365/63 198/266/63 205/265/63 +f 176/367/86 177/366/86 197/383/86 200/384/86 +f 172/362/16 127/361/16 170/385/16 193/386/16 +f 193/242/14 103/241/14 82/387/14 172/388/14 +f 44/389/16 43/390/16 77/391/16 72/72/16 71/71/16 79/392/16 +f 161/393/14 169/290/14 170/289/14 127/294/14 130/293/14 +f 83/89/87 173/88/87 172/394/87 82/395/87 +f 96/143/14 186/84/14 188/83/14 190/235/14 100/192/14 98/193/14 +f 62/138/14 59/137/14 149/325/14 152/326/14 +o chassis-fender-left_fender-left +v -2.248215 1.790193 2.516953 +v -2.248215 1.760275 2.597573 +v -1.964961 3.775234 2.514266 +v -1.964961 3.775234 2.600259 +v -1.227716 1.790193 2.516953 +v -1.227716 1.760275 2.597573 +v -1.227716 3.775234 2.514266 +v -1.227716 3.775234 2.600259 +v -2.248215 1.618749 2.455036 +v -2.248215 1.568168 2.524579 +v -1.227716 1.568168 2.524579 +v -1.227716 1.618749 2.455036 +v -2.248215 1.477421 2.359885 +v -2.248215 1.398187 2.393303 +v -1.227716 1.398187 2.393303 +v -1.227716 1.477421 2.359885 +v -2.248215 1.178246 1.657272 +v -2.248215 1.115317 1.715878 +v -1.227716 1.115317 1.715878 +v -1.227716 1.178246 1.657272 +v -2.248215 1.075977 1.549947 +v -2.248215 1.031830 1.623743 +v -1.227716 1.031830 1.623743 +v -1.227716 1.075977 1.549947 +v -2.248215 0.982369 1.499082 +v -2.248215 0.975286 1.584783 +v -1.227716 0.975286 1.584783 +v -1.227716 0.982369 1.499082 +v -2.248215 -1.605134 1.542124 +v -2.248215 -1.612217 1.627824 +v -1.227716 -1.612217 1.627824 +v -1.227716 -1.605134 1.542124 +v -2.248215 3.470147 2.514679 +v -2.248215 3.465549 2.599846 +v -1.227716 3.470147 2.514679 +v -1.227716 3.465548 2.599846 +vt 0.683133 0.664796 +vt 0.703679 0.664796 +vt 0.703679 0.667954 +vt 0.683133 0.667954 +vt 0.703679 0.688500 +vt 0.683133 0.688500 +vt 0.683133 0.691658 +vt 0.703679 0.691658 +vt 0.703679 0.709046 +vt 0.683133 0.709046 +vt 0.724225 0.709046 +vt 0.724225 0.709046 +vt 0.703679 0.709046 +vt 0.662587 0.691658 +vt 0.662587 0.709046 +vt 0.724225 0.691658 +vt 0.724225 0.709046 +vt 0.703679 0.709046 +vt 0.683133 0.709046 +vt 0.703679 0.647408 +vt 0.683133 0.647408 +vt 0.683133 0.647408 +vt 0.703679 0.647408 +vt 0.662587 0.709046 +vt 0.662587 0.709046 +vt 0.683133 0.709046 +vt 0.683133 0.709046 +vt 0.662587 0.709046 +vt 0.683133 0.647408 +vt 0.703679 0.647408 +vt 0.703679 0.709046 +vt 0.724225 0.709046 +vt 0.724225 0.709046 +vt 0.703679 0.709046 +vt 0.683133 0.647408 +vt 0.703679 0.647408 +vt 0.683133 0.709046 +vt 0.703679 0.709046 +vt 0.683133 0.709046 +vt 0.662587 0.709046 +vt 0.683133 0.647408 +vt 0.703679 0.647408 +vt 0.662587 0.709046 +vt 0.683133 0.709046 +vt 0.662587 0.709046 +vt 0.683133 0.647408 +vt 0.703679 0.647408 +vt 0.724225 0.709046 +vt 0.703679 0.709046 +vt 0.703679 0.729592 +vt 0.683133 0.729592 +vt 0.683133 0.647408 +vt 0.703679 0.647408 +vt 0.724225 0.709046 +vt 0.724225 0.688500 +vt 0.662587 0.688500 +vn -0.7353 0.6775 0.0182 +vn 0.0000 1.0000 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 -0.3552 0.9348 +vn 0.0000 -0.0014 -1.0000 +vn 0.0000 -0.0013 1.0000 +vn 0.0000 -0.6112 0.7914 +vn -1.0000 0.0000 0.0000 +vn 0.0000 0.3397 -0.9405 +vn 0.0000 0.9201 -0.3918 +vn 0.0000 0.5585 -0.8295 +vn 0.0000 -0.7410 0.6715 +vn 0.0000 -0.9228 0.3853 +vn 0.0000 0.7240 -0.6899 +vn 0.0000 -0.0166 -0.9999 +vn 0.0000 0.4774 -0.8787 +vn 0.0000 -0.5674 0.8235 +vn 0.0000 -0.9966 -0.0824 +vn 0.0000 0.0166 0.9999 +usemtl Material +s off +f 238/396/88 239/397/88 209/398/88 208/399/88 +f 208/399/89 209/398/89 213/400/89 212/401/89 +f 240/402/90 241/403/90 211/404/90 210/405/90 +f 211/404/91 207/406/91 215/407/91 216/408/91 +f 238/409/92 240/402/92 210/405/92 206/410/92 +f 241/403/93 239/411/93 207/406/93 211/404/93 +f 216/408/94 215/407/94 219/412/94 220/413/94 +f 210/405/90 211/404/90 216/408/90 217/414/90 +f 207/415/95 206/416/95 214/417/95 215/418/95 +f 206/410/96 210/405/96 217/414/96 214/419/96 +f 218/420/97 221/421/97 225/422/97 222/423/97 +f 217/414/90 216/408/90 220/413/90 221/421/90 +f 214/419/98 217/414/98 221/421/98 218/420/98 +f 215/418/95 214/417/95 218/424/95 219/425/95 +f 224/426/99 223/427/99 227/428/99 228/429/99 +f 219/425/95 218/424/95 222/430/95 223/431/95 +f 220/413/100 219/412/100 223/427/100 224/426/100 +f 221/421/90 220/413/90 224/426/90 225/422/90 +f 229/432/90 228/429/90 232/433/90 233/434/90 +f 225/422/90 224/426/90 228/429/90 229/432/90 +f 222/423/101 225/422/101 229/432/101 226/435/101 +f 223/431/95 222/430/95 226/436/95 227/437/95 +f 230/438/102 233/434/102 237/439/102 234/440/102 +f 226/435/103 229/432/103 233/434/103 230/438/103 +f 227/437/95 226/436/95 230/441/95 231/442/95 +f 228/429/104 227/428/104 231/443/104 232/433/104 +f 237/439/105 236/444/105 235/445/105 234/446/105 +f 231/442/95 230/441/95 234/447/95 235/448/95 +f 232/433/106 231/443/106 235/449/106 236/444/106 +f 233/434/90 232/433/90 236/444/90 237/439/90 +f 213/400/93 209/450/93 239/411/93 241/403/93 +f 208/451/92 212/401/92 240/402/92 238/409/92 +f 212/401/90 213/400/90 241/403/90 240/402/90 +f 206/416/95 207/415/95 239/397/95 238/396/95 +o chassis-fender-right_fender-right +v 2.252910 1.790193 2.516953 +v 2.252910 1.760275 2.597573 +v 1.969656 3.775234 2.514266 +v 1.969656 3.775234 2.600259 +v 1.232411 1.790193 2.516953 +v 1.232411 1.760275 2.597573 +v 1.232411 3.775234 2.514266 +v 1.232411 3.775234 2.600259 +v 2.252910 1.618749 2.455036 +v 2.252910 1.568168 2.524579 +v 1.232411 1.568168 2.524579 +v 1.232411 1.618749 2.455036 +v 2.252910 1.477421 2.359885 +v 2.252910 1.398187 2.393303 +v 1.232411 1.398187 2.393303 +v 1.232411 1.477421 2.359885 +v 2.252910 1.178246 1.657272 +v 2.252910 1.115317 1.715878 +v 1.232411 1.115317 1.715878 +v 1.232411 1.178246 1.657272 +v 2.252910 1.075977 1.549947 +v 2.252910 1.031830 1.623743 +v 1.232411 1.031830 1.623743 +v 1.232411 1.075977 1.549947 +v 2.252910 0.982369 1.499082 +v 2.252910 0.975286 1.584783 +v 1.232411 0.975286 1.584783 +v 1.232411 0.982369 1.499082 +v 2.252910 -1.605134 1.542124 +v 2.252910 -1.612217 1.627824 +v 1.232411 -1.612217 1.627824 +v 1.232411 -1.605134 1.542124 +v 2.252910 3.470147 2.514679 +v 2.252910 3.465549 2.599846 +v 1.232411 3.470147 2.514679 +v 1.232411 3.465548 2.599846 +vt 0.673290 0.664796 +vt 0.673290 0.667954 +vt 0.693836 0.667954 +vt 0.693836 0.664796 +vt 0.673290 0.688500 +vt 0.693836 0.688500 +vt 0.673290 0.691658 +vt 0.673290 0.709046 +vt 0.693836 0.709046 +vt 0.693836 0.691658 +vt 0.693836 0.709046 +vt 0.714382 0.709046 +vt 0.714382 0.709046 +vt 0.652744 0.691658 +vt 0.652744 0.709046 +vt 0.714382 0.691658 +vt 0.693836 0.709046 +vt 0.714382 0.709046 +vt 0.673290 0.709046 +vt 0.693836 0.647408 +vt 0.693836 0.647408 +vt 0.673290 0.647408 +vt 0.673290 0.647408 +vt 0.652744 0.709046 +vt 0.652744 0.709046 +vt 0.652744 0.709046 +vt 0.673290 0.709046 +vt 0.673290 0.709046 +vt 0.693836 0.647408 +vt 0.673290 0.647408 +vt 0.693836 0.709046 +vt 0.693836 0.709046 +vt 0.714382 0.709046 +vt 0.714382 0.709046 +vt 0.693836 0.647408 +vt 0.673290 0.647408 +vt 0.673290 0.709046 +vt 0.673290 0.709046 +vt 0.693836 0.709046 +vt 0.652744 0.709046 +vt 0.693836 0.647408 +vt 0.673290 0.647408 +vt 0.652744 0.709046 +vt 0.652744 0.709046 +vt 0.673290 0.709046 +vt 0.693836 0.647408 +vt 0.673290 0.647408 +vt 0.714382 0.709046 +vt 0.673290 0.729592 +vt 0.693836 0.729592 +vt 0.693836 0.709046 +vt 0.693836 0.647408 +vt 0.673290 0.647408 +vt 0.714382 0.709046 +vt 0.714382 0.688500 +vt 0.652744 0.688500 +vn 0.7353 0.6775 0.0182 +vn 0.0000 1.0000 0.0000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 -0.3552 0.9348 +vn 0.0000 -0.0014 -1.0000 +vn -0.0000 -0.0013 1.0000 +vn 0.0000 -0.6112 0.7914 +vn 1.0000 -0.0000 0.0000 +vn 0.0000 0.3397 -0.9405 +vn 0.0000 0.9201 -0.3918 +vn 0.0000 0.5585 -0.8295 +vn 0.0000 -0.7410 0.6715 +vn 0.0000 -0.9228 0.3853 +vn 0.0000 0.7240 -0.6899 +vn 0.0000 -0.0166 -0.9999 +vn 0.0000 0.4774 -0.8787 +vn 0.0000 -0.5674 0.8235 +vn 0.0000 -0.9966 -0.0824 +vn 0.0000 0.0166 0.9999 +usemtl Material.006 +s off +f 274/452/107 244/453/107 245/454/107 275/455/107 +f 244/453/108 248/456/108 249/457/108 245/454/108 +f 276/458/109 246/459/109 247/460/109 277/461/109 +f 247/460/110 252/462/110 251/463/110 243/464/110 +f 274/465/111 242/466/111 246/459/111 276/458/111 +f 277/461/112 247/460/112 243/464/112 275/467/112 +f 252/462/113 256/468/113 255/469/113 251/463/113 +f 246/459/109 253/470/109 252/462/109 247/460/109 +f 243/471/114 251/472/114 250/473/114 242/474/114 +f 242/466/115 250/475/115 253/470/115 246/459/115 +f 254/476/116 258/477/116 261/478/116 257/479/116 +f 253/470/109 257/479/109 256/468/109 252/462/109 +f 250/475/117 254/476/117 257/479/117 253/470/117 +f 251/472/114 255/480/114 254/481/114 250/473/114 +f 260/482/118 264/483/118 263/484/118 259/485/118 +f 255/480/114 259/486/114 258/487/114 254/481/114 +f 256/468/119 260/482/119 259/485/119 255/469/119 +f 257/479/109 261/478/109 260/482/109 256/468/109 +f 265/488/109 269/489/109 268/490/109 264/483/109 +f 261/478/109 265/488/109 264/483/109 260/482/109 +f 258/477/120 262/491/120 265/488/120 261/478/120 +f 259/486/114 263/492/114 262/493/114 258/487/114 +f 266/494/121 270/495/121 273/496/121 269/489/121 +f 262/491/122 266/494/122 269/489/122 265/488/122 +f 263/492/114 267/497/114 266/498/114 262/493/114 +f 264/483/123 268/490/123 267/499/123 263/484/123 +f 273/496/124 270/500/124 271/501/124 272/502/124 +f 267/497/114 271/503/114 270/504/114 266/498/114 +f 268/490/125 272/502/125 271/505/125 267/499/125 +f 269/489/109 273/496/109 272/502/109 268/490/109 +f 249/457/112 277/461/112 275/467/112 245/506/112 +f 244/507/111 274/465/111 276/458/111 248/456/111 +f 248/456/109 276/458/109 277/461/109 249/457/109 +f 242/474/114 274/452/114 275/455/114 243/471/114 +o chassis-bumper_Bumper +v -2.054904 4.148100 1.306946 +v -2.054904 4.148100 1.733416 +v -2.054904 4.295115 1.306946 +v -2.054904 4.295115 1.733416 +v 2.150561 4.148100 1.306946 +v 2.150561 4.148100 1.733416 +v 2.150561 4.295115 1.306946 +v 2.150561 4.295115 1.733416 +v -1.015229 4.295115 1.306946 +v -1.015229 4.295115 1.733416 +v -1.015229 4.148100 1.306946 +v -1.015229 4.148100 1.733416 +v -0.846180 4.295115 1.733416 +v -0.846180 4.148100 1.306946 +v -0.846180 4.295115 1.306946 +v -0.846180 4.148100 1.733416 +v 0.819656 4.295115 1.733416 +v 0.819656 4.148100 1.306946 +v 0.819656 4.295115 1.306946 +v 0.819656 4.148100 1.733416 +v 1.000342 4.295115 1.733416 +v 1.000342 4.148100 1.306946 +v 1.000342 4.295115 1.306946 +v 1.000342 4.148100 1.733416 +v -0.846180 3.151901 1.733416 +v -1.015229 3.151901 1.733416 +v -1.015229 3.151901 1.306946 +v -0.846180 3.151901 1.306946 +v 1.000342 3.151901 1.733416 +v 0.819656 3.151901 1.733416 +v 0.819656 3.151901 1.306946 +v 1.000342 3.151901 1.306946 +vt 0.303628 0.900609 +vt 0.322333 0.900609 +vt 0.322333 0.919314 +vt 0.303628 0.919314 +vt 0.303628 0.932903 +vt 0.322333 0.932903 +vt 0.322333 0.938019 +vt 0.303628 0.938019 +vt 0.322333 0.956724 +vt 0.303628 0.956724 +vt 0.303628 0.970805 +vt 0.322333 0.970805 +vt 0.322333 0.975429 +vt 0.303628 0.975429 +vt 0.298512 0.938019 +vt 0.298512 0.956724 +vt 0.336414 0.938019 +vt 0.341038 0.938019 +vt 0.341038 0.956724 +vt 0.336414 0.956724 +vt 0.335662 0.938019 +vt 0.335662 0.956724 +vt 0.284923 0.938019 +vt 0.289547 0.938019 +vt 0.289547 0.956724 +vt 0.284923 0.956724 +vt 0.336414 0.956724 +vt 0.335662 0.956724 +vt 0.322333 0.923939 +vt 0.303628 0.923939 +vt 0.303628 0.962644 +vt 0.322333 0.962644 +vt 0.322333 0.970053 +vt 0.303628 0.970053 +vt 0.328253 0.938019 +vt 0.328253 0.956724 +vt 0.290299 0.938019 +vt 0.290299 0.956724 +vt 0.322333 0.924690 +vt 0.303628 0.924690 +vt 0.327449 0.938019 +vt 0.327449 0.956724 +vt 0.297708 0.956724 +vt 0.298512 0.956724 +vt 0.297708 0.956724 +vt 0.297708 0.938019 +vt 0.322333 0.932100 +vt 0.303628 0.932100 +vt 0.322333 0.961840 +vt 0.303628 0.961840 +vt 0.303628 0.970053 +vt 0.322333 0.970053 +vt 0.322333 0.970805 +vt 0.303628 0.970805 +vt 0.303628 0.961840 +vt 0.322333 0.961840 +vt 0.322333 0.962644 +vt 0.303628 0.962644 +vt 0.328253 0.956724 +vt 0.327449 0.956724 +vt 0.290299 0.956724 +vt 0.289547 0.956724 +vn -1.0000 0.0000 0.0000 +vn 0.0000 1.0000 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 0.0000 0.0000 1.0000 +usemtl Material +s off +f 278/508/126 279/509/126 281/510/126 280/511/126 +f 300/512/127 298/513/127 285/514/127 284/515/127 +f 284/515/128 285/514/128 283/516/128 282/517/128 +f 288/518/129 289/519/129 279/520/129 278/521/129 +f 300/522/130 284/515/130 282/517/130 299/523/130 +f 287/524/131 281/525/131 279/526/131 289/527/131 +f 290/528/131 287/524/131 289/527/131 293/529/131 +f 280/530/130 286/531/130 288/532/130 278/533/130 +f 293/529/131 289/527/131 303/534/131 302/535/131 +f 280/511/127 281/510/127 287/536/127 286/537/127 +f 295/538/129 297/539/129 293/540/129 291/541/129 +f 294/542/131 290/528/131 293/529/131 297/543/131 +f 286/531/130 292/544/130 291/545/130 288/532/130 +f 286/537/127 287/536/127 290/546/127 292/547/127 +f 298/548/131 294/542/131 297/543/131 301/549/131 +f 295/550/130 299/523/130 309/551/130 308/552/130 +f 292/544/130 296/553/130 295/550/130 291/545/130 +f 292/547/127 290/546/127 294/554/127 296/555/127 +f 282/517/129 283/516/129 301/556/129 299/557/129 +f 285/514/131 298/548/131 301/549/131 283/516/131 +f 296/553/130 300/522/130 299/523/130 295/550/130 +f 296/555/127 294/554/127 298/513/127 300/512/127 +f 305/558/129 302/559/129 303/560/129 304/561/129 +f 309/562/129 306/563/129 307/564/129 308/565/129 +f 291/541/128 293/540/128 302/559/128 305/558/128 +f 297/539/126 295/538/126 308/565/126 307/564/126 +f 301/549/131 297/543/131 307/566/131 306/567/131 +f 299/557/128 301/556/128 306/563/128 309/562/128 +f 289/519/126 288/518/126 304/561/126 303/560/126 +f 288/532/130 291/545/130 305/568/130 304/569/130 +o chassis-cannister_Cannister +v -1.498120 -4.596298 2.097742 +v -1.498120 -4.596298 3.647724 +v -1.498120 -4.005651 2.097742 +v -1.498120 -4.005651 3.647724 +v -0.297338 -4.596298 2.097742 +v -0.297338 -4.596298 3.647724 +v -0.297338 -4.005651 2.097742 +v -0.297338 -4.005651 3.647724 +v -0.779052 -4.005651 2.097742 +v -1.016407 -4.005651 2.097742 +v -1.016407 -4.005651 3.647724 +v -0.779052 -4.005651 3.647724 +v -1.016407 -4.596298 2.097742 +v -0.779052 -4.596298 2.097742 +v -0.779052 -4.596298 3.647724 +v -1.016407 -4.596298 3.647724 +v -1.016407 -4.119907 3.721184 +v -0.779052 -4.119907 3.721184 +v -1.016407 -4.710554 2.171202 +v -0.779052 -4.710554 2.171202 +v -0.779052 -4.710554 3.721184 +v -1.016407 -4.710554 3.721184 +vt 0.306872 0.893900 +vt 0.328932 0.893900 +vt 0.328932 0.915960 +vt 0.306872 0.915960 +vt 0.306872 0.930666 +vt 0.328932 0.930666 +vt 0.328932 0.938019 +vt 0.306872 0.938019 +vt 0.328932 0.960079 +vt 0.306872 0.960079 +vt 0.306872 0.974786 +vt 0.328932 0.974786 +vt 0.328932 0.982139 +vt 0.306872 0.982139 +vt 0.299519 0.938019 +vt 0.299519 0.960079 +vt 0.343638 0.938019 +vt 0.350992 0.938019 +vt 0.350992 0.960079 +vt 0.343638 0.960079 +vt 0.336285 0.938019 +vt 0.336285 0.960079 +vt 0.306872 0.967432 +vt 0.328932 0.967432 +vt 0.328932 0.967432 +vt 0.306872 0.967432 +vt 0.284812 0.938019 +vt 0.292166 0.938019 +vt 0.292166 0.960079 +vt 0.284812 0.960079 +vt 0.328932 0.923313 +vt 0.328932 0.923313 +vt 0.328932 0.930666 +vt 0.306872 0.923313 +vt 0.336285 0.938019 +vt 0.343638 0.938019 +vt 0.343638 0.960079 +vt 0.336285 0.960079 +vt 0.328932 0.974786 +vt 0.306872 0.974786 +vt 0.299519 0.960079 +vt 0.292166 0.960079 +vn -1.0000 0.0000 0.0000 +vn 0.0000 1.0000 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 0.0000 0.0000 1.0000 +vn 0.0000 0.5408 0.8411 +vn 0.0000 -0.5408 -0.8411 +usemtl Material +s off +f 310/570/132 311/571/132 313/572/132 312/573/132 +f 318/574/133 321/575/133 317/576/133 316/577/133 +f 316/577/134 317/576/134 315/578/134 314/579/134 +f 322/580/135 325/581/135 311/582/135 310/583/135 +f 318/584/136 316/577/136 314/579/136 323/585/136 +f 320/586/137 313/587/137 311/588/137 325/589/137 +f 317/576/137 321/590/137 324/591/137 315/578/137 +f 323/592/134 324/593/134 330/594/134 329/595/134 +f 312/596/136 319/597/136 322/598/136 310/599/136 +f 319/597/136 318/584/136 323/585/136 322/598/136 +f 314/579/135 315/578/135 324/593/135 323/592/135 +f 321/575/138 320/600/138 326/601/138 327/602/138 +f 312/573/133 313/572/133 320/600/133 319/603/133 +f 319/603/133 320/600/133 321/575/133 318/574/133 +f 327/604/137 326/605/137 331/606/137 330/607/137 +f 329/595/135 330/594/135 331/608/135 328/609/135 +f 324/591/134 321/590/134 327/604/134 330/607/134 +f 325/581/132 322/580/132 328/609/132 331/608/132 +f 320/586/132 325/589/132 331/606/132 326/605/132 +f 322/598/139 323/585/139 329/610/139 328/611/139 +o chassis-lamp-left_lamp-left +v -1.324289 3.825797 3.192716 +v -1.324289 3.263589 3.192716 +v -1.143598 3.825797 3.126951 +v -1.143598 3.263589 3.126950 +v -1.047455 3.825797 2.960425 +v -1.047455 3.263589 2.960425 +v -1.080845 3.825797 2.771060 +v -1.080845 3.263589 2.771060 +v -1.228145 3.825797 2.647460 +v -1.228145 3.263589 2.647460 +v -1.420432 3.825797 2.647460 +v -1.420432 3.263589 2.647460 +v -1.567732 3.825797 2.771060 +v -1.567732 3.263589 2.771060 +v -1.601122 3.825797 2.960425 +v -1.601122 3.263589 2.960425 +v -1.504979 3.825797 3.126951 +v -1.504979 3.263589 3.126950 +vt 0.363359 0.944968 +vt 0.363359 0.980203 +vt 0.355529 0.980203 +vt 0.355529 0.944968 +vt 0.347700 0.980203 +vt 0.347700 0.944968 +vt 0.339870 0.980203 +vt 0.339870 0.944968 +vt 0.332040 0.980203 +vt 0.332040 0.944968 +vt 0.324210 0.980203 +vt 0.324210 0.944968 +vt 0.316380 0.980203 +vt 0.316380 0.944968 +vt 0.308550 0.980203 +vt 0.308550 0.944968 +vt 0.321379 0.940307 +vt 0.310508 0.944264 +vt 0.299637 0.940307 +vt 0.293852 0.930288 +vt 0.295861 0.918895 +vt 0.304723 0.911459 +vt 0.316292 0.911459 +vt 0.325154 0.918895 +vt 0.327163 0.930288 +vt 0.300721 0.980203 +vt 0.300721 0.944968 +vt 0.292891 0.980203 +vt 0.292891 0.944968 +vt 0.345742 0.944264 +vt 0.356613 0.940307 +vt 0.362398 0.930288 +vt 0.360389 0.918895 +vt 0.351527 0.911459 +vt 0.339958 0.911459 +vt 0.331096 0.918895 +vt 0.329087 0.930288 +vt 0.334871 0.940307 +vn 0.3420 -0.0000 0.9397 +vn 0.8660 0.0000 0.5000 +vn 0.9848 0.0000 -0.1736 +vn 0.6428 0.0000 -0.7660 +vn 0.0000 0.0000 -1.0000 +vn -0.6428 0.0000 -0.7660 +vn -0.9848 0.0000 -0.1736 +vn 0.0000 -1.0000 -0.0000 +vn -0.8660 0.0000 0.5000 +vn -0.3420 -0.0000 0.9397 +vn 0.0000 1.0000 -0.0000 +usemtl Material +s off +f 332/612/140 333/613/140 335/614/140 334/615/140 +f 334/615/141 335/614/141 337/616/141 336/617/141 +f 336/617/142 337/616/142 339/618/142 338/619/142 +f 338/619/143 339/618/143 341/620/143 340/621/143 +f 340/621/144 341/620/144 343/622/144 342/623/144 +f 342/623/145 343/622/145 345/624/145 344/625/145 +f 344/625/146 345/624/146 347/626/146 346/627/146 +f 335/628/147 333/629/147 349/630/147 347/631/147 345/632/147 343/633/147 341/634/147 339/635/147 337/636/147 +f 346/627/148 347/626/148 349/637/148 348/638/148 +f 348/638/149 349/637/149 333/639/149 332/640/149 +f 332/641/150 334/642/150 336/643/150 338/644/150 340/645/150 342/646/150 344/647/150 346/648/150 348/649/150 +o chassis-lamp-right_lamp-right +v 1.257088 3.825797 3.192716 +v 1.257088 3.263589 3.192716 +v 1.437779 3.825797 3.126951 +v 1.437779 3.263589 3.126950 +v 1.533922 3.825797 2.960425 +v 1.533922 3.263589 2.960425 +v 1.500532 3.825797 2.771060 +v 1.500532 3.263589 2.771060 +v 1.353232 3.825797 2.647460 +v 1.353232 3.263589 2.647460 +v 1.160945 3.825797 2.647460 +v 1.160945 3.263589 2.647460 +v 1.013645 3.825797 2.771060 +v 1.013645 3.263589 2.771060 +v 0.980255 3.825797 2.960425 +v 0.980255 3.263589 2.960425 +v 1.076398 3.825797 3.126951 +v 1.076398 3.263589 3.126950 +vt 0.363359 0.944968 +vt 0.363359 0.980203 +vt 0.355529 0.980203 +vt 0.355529 0.944968 +vt 0.347700 0.980203 +vt 0.347700 0.944968 +vt 0.339870 0.980203 +vt 0.339870 0.944968 +vt 0.332040 0.980203 +vt 0.332040 0.944968 +vt 0.324210 0.980203 +vt 0.324210 0.944968 +vt 0.316380 0.980203 +vt 0.316380 0.944968 +vt 0.308550 0.980203 +vt 0.308550 0.944968 +vt 0.321379 0.940307 +vt 0.310508 0.944264 +vt 0.299637 0.940307 +vt 0.293852 0.930288 +vt 0.295861 0.918895 +vt 0.304723 0.911459 +vt 0.316292 0.911459 +vt 0.325154 0.918895 +vt 0.327163 0.930288 +vt 0.300721 0.980203 +vt 0.300721 0.944968 +vt 0.292891 0.980203 +vt 0.292891 0.944968 +vt 0.345742 0.944264 +vt 0.356613 0.940307 +vt 0.362398 0.930288 +vt 0.360389 0.918895 +vt 0.351527 0.911459 +vt 0.339958 0.911459 +vt 0.331096 0.918895 +vt 0.329087 0.930288 +vt 0.334871 0.940307 +vn 0.3420 -0.0000 0.9397 +vn 0.8660 -0.0000 0.5000 +vn 0.9848 0.0000 -0.1736 +vn 0.6428 0.0000 -0.7660 +vn 0.0000 0.0000 -1.0000 +vn -0.6428 0.0000 -0.7660 +vn -0.9848 0.0000 -0.1736 +vn 0.0000 -1.0000 0.0000 +vn -0.8660 -0.0000 0.5000 +vn -0.3420 -0.0000 0.9397 +vn 0.0000 1.0000 -0.0000 +usemtl Material.005 +s off +f 350/650/151 351/651/151 353/652/151 352/653/151 +f 352/653/152 353/652/152 355/654/152 354/655/152 +f 354/655/153 355/654/153 357/656/153 356/657/153 +f 356/657/154 357/656/154 359/658/154 358/659/154 +f 358/659/155 359/658/155 361/660/155 360/661/155 +f 360/661/156 361/660/156 363/662/156 362/663/156 +f 362/663/157 363/662/157 365/664/157 364/665/157 +f 353/666/158 351/667/158 367/668/158 365/669/158 363/670/158 361/671/158 359/672/158 357/673/158 355/674/158 +f 364/665/159 365/664/159 367/675/159 366/676/159 +f 366/676/160 367/675/160 351/677/160 350/678/160 +f 350/679/161 352/680/161 354/681/161 356/682/161 358/683/161 360/684/161 362/685/161 364/686/161 366/687/161 +o chassis-spare_Wheel +v 2.023177 -3.732064 2.891503 +v 1.218354 -4.292669 2.891503 +v 1.892179 -3.732064 2.360024 +v 1.179544 -4.292669 2.734044 +v 1.529196 -3.732064 1.950301 +v 1.072005 -4.292669 2.612658 +v 1.017383 -3.732064 1.756196 +v 0.920372 -4.292669 2.555151 +v 0.473989 -3.732064 1.822176 +v 0.759384 -4.292669 2.574699 +v 0.023501 -3.732064 2.133126 +v 0.625920 -4.292669 2.666822 +v -0.230881 -3.732064 2.617811 +v 0.550555 -4.292669 2.810417 +v -0.230881 -3.732064 3.165195 +v 0.550555 -4.292669 2.972588 +v 0.023501 -3.732064 3.649880 +v 0.625920 -4.292669 3.116184 +v 0.473989 -3.732064 3.960829 +v 0.759384 -4.292669 3.208307 +v 1.017383 -3.732064 4.026810 +v 0.920372 -4.292669 3.227855 +v 1.529196 -3.732064 3.832704 +v 1.072005 -4.292669 3.170348 +v 1.892179 -3.732064 3.422981 +v 1.179544 -4.292669 3.048961 +v 1.892179 -4.521030 2.360024 +v 2.023177 -4.521030 2.891503 +v 1.529196 -4.521030 1.950301 +v 1.017383 -4.521030 1.756196 +v 0.473990 -4.521030 1.822176 +v 0.023501 -4.521030 2.133126 +v -0.230881 -4.521030 2.617811 +v -0.230881 -4.521030 3.165195 +v 0.023501 -4.521030 3.649880 +v 0.473990 -4.521030 3.960829 +v 1.017383 -4.521030 4.026810 +v 1.529196 -4.521030 3.832704 +v 1.892179 -4.521030 3.422981 +v 1.552601 -4.521030 2.538249 +v 1.639670 -4.521030 2.891503 +v 1.311339 -4.521030 2.265921 +v 0.971156 -4.521030 2.136907 +v 0.609983 -4.521030 2.180762 +v 0.310560 -4.521030 2.387438 +v 0.141482 -4.521030 2.709590 +v 0.141482 -4.521030 3.073416 +v 0.310560 -4.521030 3.395568 +v 0.609983 -4.521030 3.602244 +v 0.971156 -4.521030 3.646099 +v 1.311339 -4.521030 3.517084 +v 1.552601 -4.521030 3.244757 +v 1.347870 -4.292669 2.645700 +v 1.408455 -4.292669 2.891503 +v 1.179995 -4.292669 2.456207 +v 0.943286 -4.292669 2.366436 +v 0.691973 -4.292669 2.396951 +v 0.483627 -4.292669 2.540762 +v 0.365978 -4.292669 2.764923 +v 0.365978 -4.292669 3.018083 +v 0.483627 -4.292669 3.242244 +v 0.691973 -4.292669 3.386055 +v 0.943286 -4.292669 3.416570 +v 1.179995 -4.292669 3.326798 +v 1.347870 -4.292669 3.137306 +v 1.179544 -4.420413 2.734044 +v 1.218354 -4.420413 2.891503 +v 1.072005 -4.420413 2.612658 +v 0.920372 -4.420413 2.555151 +v 0.759384 -4.420413 2.574699 +v 0.625920 -4.420413 2.666822 +v 0.550555 -4.420413 2.810417 +v 0.550555 -4.420413 2.972588 +v 0.625920 -4.420413 3.116184 +v 0.759384 -4.420413 3.208307 +v 0.920372 -4.420413 3.227855 +v 1.072005 -4.420413 3.170348 +v 1.179544 -4.420413 3.048961 +vt 0.111861 0.941309 +vt 0.111861 0.986764 +vt 0.104868 0.986764 +vt 0.104868 0.941309 +vt 0.097875 0.986764 +vt 0.097875 0.941309 +vt 0.090882 0.986764 +vt 0.090882 0.941309 +vt 0.083889 0.986764 +vt 0.083889 0.941309 +vt 0.076896 0.986764 +vt 0.076896 0.941309 +vt 0.069903 0.986764 +vt 0.069903 0.941309 +vt 0.062910 0.986764 +vt 0.062910 0.941309 +vt 0.055917 0.986764 +vt 0.055917 0.941309 +vt 0.048924 0.986764 +vt 0.048924 0.941309 +vt 0.041931 0.986764 +vt 0.041931 0.941309 +vt 0.034938 0.986764 +vt 0.034938 0.941309 +vt 0.050096 0.919361 +vt 0.048999 0.922254 +vt 0.048999 0.922254 +vt 0.050096 0.919361 +vt 0.027945 0.986764 +vt 0.027945 0.941309 +vt 0.020952 0.986764 +vt 0.020952 0.941309 +vt 0.089134 0.940400 +vt 0.099273 0.937901 +vt 0.107090 0.930976 +vt 0.110793 0.921212 +vt 0.109534 0.910845 +vt 0.103602 0.902251 +vt 0.094355 0.897398 +vt 0.083912 0.897398 +vt 0.074665 0.902251 +vt 0.068733 0.910845 +vt 0.067474 0.921212 +vt 0.071178 0.930976 +vt 0.078994 0.937901 +vt 0.043679 0.933084 +vt 0.050418 0.931422 +vt 0.053818 0.937901 +vt 0.043679 0.940400 +vt 0.055614 0.926820 +vt 0.061635 0.930976 +vt 0.058075 0.920330 +vt 0.065338 0.921212 +vt 0.057238 0.913440 +vt 0.064079 0.910845 +vt 0.053295 0.907727 +vt 0.058147 0.902251 +vt 0.047149 0.904502 +vt 0.048900 0.897398 +vt 0.040209 0.904502 +vt 0.038458 0.897398 +vt 0.034063 0.907727 +vt 0.029211 0.902251 +vt 0.030120 0.913440 +vt 0.023279 0.910845 +vt 0.029283 0.920330 +vt 0.022020 0.921212 +vt 0.031744 0.926820 +vt 0.025723 0.930976 +vt 0.036940 0.931422 +vt 0.033540 0.937901 +vt 0.063210 0.940391 +vt 0.067900 0.939235 +vt 0.069950 0.943141 +vt 0.063210 0.944802 +vt 0.071515 0.936033 +vt 0.075145 0.938539 +vt 0.073227 0.931517 +vt 0.077606 0.932049 +vt 0.072645 0.926722 +vt 0.076770 0.925158 +vt 0.069902 0.922748 +vt 0.072827 0.919446 +vt 0.065625 0.920503 +vt 0.066681 0.916220 +vt 0.060795 0.920503 +vt 0.059740 0.916220 +vt 0.056519 0.922748 +vt 0.053594 0.919446 +vt 0.053775 0.926722 +vt 0.049651 0.925158 +vt 0.053193 0.931517 +vt 0.048814 0.932049 +vt 0.054906 0.936033 +vt 0.051276 0.938539 +vt 0.058521 0.939235 +vt 0.056471 0.943141 +vt 0.676491 0.698483 +vt 0.679495 0.697743 +vt 0.681181 0.700954 +vt 0.676491 0.702110 +vt 0.681811 0.695691 +vt 0.684796 0.697752 +vt 0.682908 0.692798 +vt 0.686509 0.693236 +vt 0.682535 0.689727 +vt 0.685926 0.688441 +vt 0.680778 0.687181 +vt 0.683183 0.684466 +vt 0.678038 0.685743 +vt 0.678906 0.682222 +vt 0.674945 0.685743 +vt 0.674077 0.682222 +vt 0.672205 0.687181 +vt 0.669800 0.684466 +vt 0.670448 0.689727 +vt 0.667057 0.688441 +vt 0.670075 0.692798 +vt 0.666474 0.693236 +vt 0.671172 0.695691 +vt 0.668187 0.697752 +vt 0.673487 0.697743 +vt 0.671802 0.700954 +vt 0.679495 0.697743 +vt 0.676491 0.698483 +vt 0.673487 0.697743 +vt 0.671172 0.695691 +vt 0.670075 0.692798 +vt 0.670448 0.689727 +vt 0.672205 0.687181 +vt 0.674945 0.685743 +vt 0.678038 0.685743 +vt 0.680778 0.687181 +vt 0.682535 0.689727 +vt 0.682908 0.692798 +vt 0.681811 0.695691 +vt 0.049723 0.916290 +vt 0.049723 0.916290 +vt 0.045226 0.912306 +vt 0.047965 0.913744 +vt 0.047965 0.913744 +vt 0.045226 0.912306 +vt 0.039393 0.913744 +vt 0.042132 0.912306 +vt 0.042132 0.912306 +vt 0.039393 0.913744 +vt 0.046683 0.924305 +vt 0.046683 0.924305 +vn 0.9709 0.0000 -0.2393 +vn 0.7485 0.0000 -0.6631 +vn 0.3546 0.0000 -0.9350 +vn -0.1205 -0.0000 -0.9927 +vn -0.5681 -0.0000 -0.8230 +vn -0.8855 0.0000 -0.4647 +vn -1.0000 0.0000 0.0000 +vn -0.8855 0.0000 0.4647 +vn -0.5681 -0.0000 0.8230 +vn -0.1205 -0.0000 0.9927 +vn 0.3546 0.0000 0.9350 +vn 0.7485 0.0000 0.6631 +vn 0.9709 0.0000 0.2393 +vn -0.0000 1.0000 0.0000 +vn 0.0000 -1.0000 -0.0000 +vn -0.6924 -0.7010 0.1707 +vn -0.5338 -0.7010 0.4729 +vn -0.2529 -0.7010 0.6668 +vn 0.0860 -0.7010 0.7079 +vn 0.4051 -0.7010 0.5869 +vn 0.6314 -0.7010 0.3314 +vn 0.7131 -0.7010 0.0000 +vn 0.6314 -0.7010 -0.3314 +vn 0.4051 -0.7010 -0.5869 +vn 0.0860 -0.7010 -0.7079 +vn -0.2529 -0.7010 -0.6668 +vn -0.5338 -0.7010 -0.4729 +vn -0.6924 -0.7010 -0.1707 +usemtl Material.002 +s off +f 368/688/162 395/689/162 394/690/162 370/691/162 +f 370/691/163 394/690/163 396/692/163 372/693/163 +f 372/693/164 396/692/164 397/694/164 374/695/164 +f 374/695/165 397/694/165 398/696/165 376/697/165 +f 376/697/166 398/696/166 399/698/166 378/699/166 +f 378/699/167 399/698/167 400/700/167 380/701/167 +f 380/701/168 400/700/168 401/702/168 382/703/168 +f 382/703/169 401/702/169 402/704/169 384/705/169 +f 384/705/170 402/704/170 403/706/170 386/707/170 +f 386/707/171 403/706/171 404/708/171 388/709/171 +f 388/709/172 404/708/172 405/710/172 390/711/172 +f 375/712/164 373/713/164 435/714/164 436/715/164 +f 390/711/173 405/710/173 406/716/173 392/717/173 +f 392/717/174 406/716/174 395/718/174 368/719/174 +f 368/720/175 370/721/175 372/722/175 374/723/175 376/724/175 378/725/175 380/726/175 382/727/175 384/728/175 386/729/175 388/730/175 390/731/175 392/732/175 +f 408/733/176 407/734/176 394/735/176 395/736/176 +f 407/734/176 409/737/176 396/738/176 394/735/176 +f 409/737/176 410/739/176 397/740/176 396/738/176 +f 410/739/176 411/741/176 398/742/176 397/740/176 +f 411/741/176 412/743/176 399/744/176 398/742/176 +f 412/743/176 413/745/176 400/746/176 399/744/176 +f 413/745/176 414/747/176 401/748/176 400/746/176 +f 414/747/176 415/749/176 402/750/176 401/748/176 +f 415/749/176 416/751/176 403/752/176 402/750/176 +f 416/751/176 417/753/176 404/754/176 403/752/176 +f 417/753/176 418/755/176 405/756/176 404/754/176 +f 418/755/176 419/757/176 406/758/176 405/756/176 +f 419/757/176 408/733/176 395/736/176 406/758/176 +f 421/759/177 420/760/177 407/761/177 408/762/177 +f 420/760/178 422/763/178 409/764/178 407/761/178 +f 422/763/179 423/765/179 410/766/179 409/764/179 +f 423/765/180 424/767/180 411/768/180 410/766/180 +f 424/767/181 425/769/181 412/770/181 411/768/181 +f 425/769/182 426/771/182 413/772/182 412/770/182 +f 426/771/183 427/773/183 414/774/183 413/772/183 +f 427/773/184 428/775/184 415/776/184 414/774/184 +f 428/775/185 429/777/185 416/778/185 415/776/185 +f 429/777/186 430/779/186 417/780/186 416/778/186 +f 430/779/187 431/781/187 418/782/187 417/780/187 +f 431/781/188 432/783/188 419/784/188 418/782/188 +f 432/783/189 421/759/189 408/762/189 419/784/189 +f 369/785/176 371/786/176 420/787/176 421/788/176 +f 371/786/176 373/789/176 422/790/176 420/787/176 +f 373/789/176 375/791/176 423/792/176 422/790/176 +f 375/791/176 377/793/176 424/794/176 423/792/176 +f 377/793/176 379/795/176 425/796/176 424/794/176 +f 379/795/176 381/797/176 426/798/176 425/796/176 +f 381/797/176 383/799/176 427/800/176 426/798/176 +f 383/799/176 385/801/176 428/802/176 427/800/176 +f 385/801/176 387/803/176 429/804/176 428/802/176 +f 387/803/176 389/805/176 430/806/176 429/804/176 +f 389/805/176 391/807/176 431/808/176 430/806/176 +f 391/807/176 393/809/176 432/810/176 431/808/176 +f 393/809/176 369/785/176 421/788/176 432/810/176 +f 433/811/176 434/812/176 445/813/176 444/814/176 443/815/176 442/816/176 441/817/176 440/818/176 439/819/176 438/820/176 437/821/176 436/822/176 435/823/176 +f 391/807/172 389/805/172 443/815/172 444/814/172 +f 377/824/165 375/712/165 436/715/165 437/825/165 +f 393/809/173 391/807/173 444/814/173 445/813/173 +f 379/795/166 377/793/166 437/821/166 438/820/166 +f 369/785/174 393/809/174 445/813/174 434/812/174 +f 381/826/167 379/827/167 438/828/167 439/829/167 +f 383/799/168 381/797/168 439/819/168 440/818/168 +f 385/830/169 383/831/169 440/832/169 441/833/169 +f 371/786/162 369/785/162 434/812/162 433/811/162 +f 387/803/170 385/801/170 441/817/170 442/816/170 +f 373/713/163 371/834/163 433/835/163 435/714/163 +f 389/805/171 387/803/171 442/816/171 443/815/171 +o Wheel +v -0.394486 1.143645 0.000000 +v 0.166118 0.338822 0.000000 +v -0.394486 1.012648 -0.531478 +v 0.166118 0.300012 -0.157459 +v -0.394486 0.649665 -0.941202 +v 0.166118 0.192473 -0.278845 +v -0.394486 0.137851 -1.135307 +v 0.166119 0.040841 -0.336352 +v -0.394486 -0.405542 -1.069327 +v 0.166119 -0.120148 -0.316804 +v -0.394486 -0.856031 -0.758377 +v 0.166119 -0.253612 -0.224681 +v -0.394486 -1.110413 -0.273692 +v 0.166119 -0.328977 -0.081085 +v -0.394486 -1.110413 0.273692 +v 0.166119 -0.328977 0.081085 +v -0.394486 -0.856031 0.758377 +v 0.166119 -0.253612 0.224681 +v -0.394486 -0.405542 1.069327 +v 0.166119 -0.120148 0.316804 +v -0.394486 0.137851 1.135307 +v 0.166119 0.040841 0.336352 +v -0.394486 0.649665 0.941201 +v 0.166118 0.192473 0.278845 +v -0.394486 1.012648 0.531478 +v 0.166118 0.300012 0.157459 +v 0.394480 1.012648 -0.531478 +v 0.394480 1.143645 -0.000000 +v 0.394480 0.649665 -0.941202 +v 0.394480 0.137851 -1.135307 +v 0.394480 -0.405542 -1.069327 +v 0.394480 -0.856030 -0.758377 +v 0.394480 -1.110413 -0.273692 +v 0.394480 -1.110413 0.273692 +v 0.394480 -0.856030 0.758377 +v 0.394480 -0.405542 1.069327 +v 0.394480 0.137851 1.135307 +v 0.394480 0.649665 0.941201 +v 0.394480 1.012648 0.531478 +v 0.394480 0.673069 -0.353254 +v 0.394480 0.760138 -0.000000 +v 0.394480 0.431808 -0.625581 +v 0.394480 0.091625 -0.754596 +v 0.394480 -0.269549 -0.710741 +v 0.394480 -0.568971 -0.504065 +v 0.394480 -0.738050 -0.181913 +v 0.394480 -0.738050 0.181913 +v 0.394480 -0.568971 0.504065 +v 0.394480 -0.269549 0.710741 +v 0.394480 0.091625 0.754596 +v 0.394480 0.431808 0.625581 +v 0.394480 0.673069 0.353254 +v 0.166118 0.468339 -0.245803 +v 0.166118 0.528924 0.000000 +v 0.166118 0.300463 -0.435296 +v 0.166119 0.063755 -0.525067 +v 0.166119 -0.187559 -0.494552 +v 0.166119 -0.395905 -0.350741 +v 0.166119 -0.513554 -0.126580 +v 0.166119 -0.513554 0.126580 +v 0.166119 -0.395905 0.350741 +v 0.166119 -0.187559 0.494552 +v 0.166119 0.063755 0.525067 +v 0.166119 0.300463 0.435296 +v 0.166118 0.468339 0.245803 +v 0.293863 0.300012 -0.157459 +v 0.293863 0.338822 -0.000000 +v 0.293863 0.192473 -0.278845 +v 0.293863 0.040841 -0.336352 +v 0.293863 -0.120148 -0.316804 +v 0.293863 -0.253612 -0.224681 +v 0.293863 -0.328977 -0.081085 +v 0.293863 -0.328977 0.081085 +v 0.293863 -0.253612 0.224681 +v 0.293863 -0.120148 0.316804 +v 0.293863 0.040841 0.336352 +v 0.293863 0.192473 0.278845 +v 0.293863 0.300012 0.157459 +vt 0.111861 0.941309 +vt 0.111861 0.986764 +vt 0.104868 0.986764 +vt 0.104868 0.941309 +vt 0.097875 0.986764 +vt 0.097875 0.941309 +vt 0.090882 0.986764 +vt 0.090882 0.941309 +vt 0.083889 0.986764 +vt 0.083889 0.941309 +vt 0.076896 0.986764 +vt 0.076896 0.941309 +vt 0.069903 0.986764 +vt 0.069903 0.941309 +vt 0.062910 0.986764 +vt 0.062910 0.941309 +vt 0.055917 0.986764 +vt 0.055917 0.941309 +vt 0.048924 0.986764 +vt 0.048924 0.941309 +vt 0.041931 0.986764 +vt 0.041931 0.941309 +vt 0.034938 0.986764 +vt 0.034938 0.941309 +vt 0.050096 0.919361 +vt 0.048999 0.922254 +vt 0.048999 0.922254 +vt 0.050096 0.919361 +vt 0.027945 0.986764 +vt 0.027945 0.941309 +vt 0.020952 0.986764 +vt 0.020952 0.941309 +vt 0.089134 0.940400 +vt 0.099273 0.937901 +vt 0.107090 0.930976 +vt 0.110793 0.921212 +vt 0.109534 0.910845 +vt 0.103602 0.902251 +vt 0.094355 0.897398 +vt 0.083912 0.897398 +vt 0.074665 0.902251 +vt 0.068733 0.910845 +vt 0.067474 0.921212 +vt 0.071178 0.930976 +vt 0.078994 0.937901 +vt 0.043679 0.933084 +vt 0.050418 0.931422 +vt 0.053818 0.937901 +vt 0.043679 0.940400 +vt 0.055614 0.926820 +vt 0.061635 0.930976 +vt 0.058075 0.920330 +vt 0.065338 0.921212 +vt 0.057238 0.913440 +vt 0.064079 0.910845 +vt 0.053295 0.907727 +vt 0.058147 0.902251 +vt 0.047149 0.904502 +vt 0.048900 0.897398 +vt 0.040209 0.904502 +vt 0.038458 0.897398 +vt 0.034063 0.907727 +vt 0.029211 0.902251 +vt 0.030120 0.913440 +vt 0.023279 0.910845 +vt 0.029283 0.920330 +vt 0.022020 0.921212 +vt 0.031744 0.926820 +vt 0.025723 0.930976 +vt 0.036940 0.931422 +vt 0.033540 0.937901 +vt 0.063210 0.940391 +vt 0.067900 0.939235 +vt 0.069950 0.943141 +vt 0.063210 0.944802 +vt 0.071515 0.936033 +vt 0.075145 0.938539 +vt 0.073227 0.931517 +vt 0.077606 0.932049 +vt 0.072645 0.926722 +vt 0.076770 0.925158 +vt 0.069902 0.922748 +vt 0.072827 0.919446 +vt 0.065625 0.920503 +vt 0.066681 0.916220 +vt 0.060795 0.920503 +vt 0.059740 0.916220 +vt 0.056519 0.922748 +vt 0.053594 0.919446 +vt 0.053775 0.926722 +vt 0.049651 0.925158 +vt 0.053193 0.931517 +vt 0.048814 0.932049 +vt 0.054906 0.936033 +vt 0.051276 0.938539 +vt 0.058521 0.939235 +vt 0.056471 0.943141 +vt 0.676491 0.698483 +vt 0.679495 0.697743 +vt 0.681181 0.700954 +vt 0.676491 0.702110 +vt 0.681811 0.695691 +vt 0.684796 0.697752 +vt 0.682908 0.692798 +vt 0.686509 0.693236 +vt 0.682535 0.689727 +vt 0.685926 0.688441 +vt 0.680778 0.687181 +vt 0.683183 0.684466 +vt 0.678038 0.685743 +vt 0.678906 0.682222 +vt 0.674945 0.685743 +vt 0.674077 0.682222 +vt 0.672205 0.687181 +vt 0.669800 0.684466 +vt 0.670448 0.689727 +vt 0.667057 0.688441 +vt 0.670075 0.692798 +vt 0.666474 0.693236 +vt 0.671172 0.695691 +vt 0.668187 0.697752 +vt 0.673487 0.697743 +vt 0.671802 0.700954 +vt 0.679495 0.697743 +vt 0.676491 0.698483 +vt 0.673487 0.697743 +vt 0.671172 0.695691 +vt 0.670075 0.692798 +vt 0.670448 0.689727 +vt 0.672205 0.687181 +vt 0.674945 0.685743 +vt 0.678038 0.685743 +vt 0.680778 0.687181 +vt 0.682535 0.689727 +vt 0.682908 0.692798 +vt 0.681811 0.695691 +vt 0.049723 0.916290 +vt 0.049723 0.916290 +vt 0.045226 0.912306 +vt 0.047965 0.913744 +vt 0.047965 0.913744 +vt 0.045226 0.912306 +vt 0.039393 0.913744 +vt 0.042132 0.912306 +vt 0.042132 0.912306 +vt 0.039393 0.913744 +vt 0.046683 0.924305 +vt 0.046683 0.924305 +vn 0.0000 0.9709 -0.2393 +vn -0.0000 0.7485 -0.6631 +vn -0.0000 0.3546 -0.9350 +vn -0.0000 -0.1205 -0.9927 +vn 0.0000 -0.5681 -0.8230 +vn 0.0000 -0.8855 -0.4647 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 -0.8855 0.4647 +vn 0.0000 -0.5681 0.8230 +vn 0.0000 -0.1205 0.9927 +vn -0.0000 0.3546 0.9350 +vn -0.0000 0.7485 0.6631 +vn 0.0000 0.9709 0.2393 +vn -1.0000 -0.0000 0.0000 +vn 1.0000 0.0000 -0.0000 +vn 0.7010 -0.6924 0.1707 +vn 0.7010 -0.5338 0.4729 +vn 0.7010 -0.2529 0.6668 +vn 0.7010 0.0860 0.7079 +vn 0.7010 0.4051 0.5869 +vn 0.7010 0.6314 0.3314 +vn 0.7010 0.7131 0.0000 +vn 0.7010 0.6314 -0.3314 +vn 0.7010 0.4051 -0.5869 +vn 0.7010 0.0860 -0.7079 +vn 0.7010 -0.2529 -0.6668 +vn 0.7010 -0.5338 -0.4729 +vn 0.7010 -0.6924 -0.1707 +usemtl Material.002 +s off +f 446/836/190 473/837/190 472/838/190 448/839/190 +f 448/839/191 472/838/191 474/840/191 450/841/191 +f 450/841/192 474/840/192 475/842/192 452/843/192 +f 452/843/193 475/842/193 476/844/193 454/845/193 +f 454/845/194 476/844/194 477/846/194 456/847/194 +f 456/847/195 477/846/195 478/848/195 458/849/195 +f 458/849/196 478/848/196 479/850/196 460/851/196 +f 460/851/197 479/850/197 480/852/197 462/853/197 +f 462/853/198 480/852/198 481/854/198 464/855/198 +f 464/855/199 481/854/199 482/856/199 466/857/199 +f 466/857/200 482/856/200 483/858/200 468/859/200 +f 453/860/192 451/861/192 513/862/192 514/863/192 +f 468/859/201 483/858/201 484/864/201 470/865/201 +f 470/865/202 484/864/202 473/866/202 446/867/202 +f 446/868/203 448/869/203 450/870/203 452/871/203 454/872/203 456/873/203 458/874/203 460/875/203 462/876/203 464/877/203 466/878/203 468/879/203 470/880/203 +f 486/881/204 485/882/204 472/883/204 473/884/204 +f 485/882/204 487/885/204 474/886/204 472/883/204 +f 487/885/204 488/887/204 475/888/204 474/886/204 +f 488/887/204 489/889/204 476/890/204 475/888/204 +f 489/889/204 490/891/204 477/892/204 476/890/204 +f 490/891/204 491/893/204 478/894/204 477/892/204 +f 491/893/204 492/895/204 479/896/204 478/894/204 +f 492/895/204 493/897/204 480/898/204 479/896/204 +f 493/897/204 494/899/204 481/900/204 480/898/204 +f 494/899/204 495/901/204 482/902/204 481/900/204 +f 495/901/204 496/903/204 483/904/204 482/902/204 +f 496/903/204 497/905/204 484/906/204 483/904/204 +f 497/905/204 486/881/204 473/884/204 484/906/204 +f 499/907/205 498/908/205 485/909/205 486/910/205 +f 498/908/206 500/911/206 487/912/206 485/909/206 +f 500/911/207 501/913/207 488/914/207 487/912/207 +f 501/913/208 502/915/208 489/916/208 488/914/208 +f 502/915/209 503/917/209 490/918/209 489/916/209 +f 503/917/210 504/919/210 491/920/210 490/918/210 +f 504/919/211 505/921/211 492/922/211 491/920/211 +f 505/921/212 506/923/212 493/924/212 492/922/212 +f 506/923/213 507/925/213 494/926/213 493/924/213 +f 507/925/214 508/927/214 495/928/214 494/926/214 +f 508/927/215 509/929/215 496/930/215 495/928/215 +f 509/929/216 510/931/216 497/932/216 496/930/216 +f 510/931/217 499/907/217 486/910/217 497/932/217 +f 447/933/204 449/934/204 498/935/204 499/936/204 +f 449/934/204 451/937/204 500/938/204 498/935/204 +f 451/937/204 453/939/204 501/940/204 500/938/204 +f 453/939/204 455/941/204 502/942/204 501/940/204 +f 455/941/204 457/943/204 503/944/204 502/942/204 +f 457/943/204 459/945/204 504/946/204 503/944/204 +f 459/945/204 461/947/204 505/948/204 504/946/204 +f 461/947/204 463/949/204 506/950/204 505/948/204 +f 463/949/204 465/951/204 507/952/204 506/950/204 +f 465/951/204 467/953/204 508/954/204 507/952/204 +f 467/953/204 469/955/204 509/956/204 508/954/204 +f 469/955/204 471/957/204 510/958/204 509/956/204 +f 471/957/204 447/933/204 499/936/204 510/958/204 +f 511/959/204 512/960/204 523/961/204 522/962/204 521/963/204 520/964/204 519/965/204 518/966/204 517/967/204 516/968/204 515/969/204 514/970/204 513/971/204 +f 469/955/200 467/953/200 521/963/200 522/962/200 +f 455/972/193 453/860/193 514/863/193 515/973/193 +f 471/957/201 469/955/201 522/962/201 523/961/201 +f 457/943/194 455/941/194 515/969/194 516/968/194 +f 447/933/202 471/957/202 523/961/202 512/960/202 +f 459/974/195 457/975/195 516/976/195 517/977/195 +f 461/947/196 459/945/196 517/967/196 518/966/196 +f 463/978/197 461/979/197 518/980/197 519/981/197 +f 449/934/190 447/933/190 512/960/190 511/959/190 +f 465/951/198 463/949/198 519/965/198 520/964/198 +f 451/861/191 449/982/191 511/983/191 513/862/191 +f 467/953/199 465/951/199 520/964/199 521/963/199 +o Axis3d +v 0.000000 -0.000000 0.000000 +v -0.100000 0.000000 -0.000000 +l 524 525 diff --git a/examples/src/Jeep.png b/examples/src/Jeep.png new file mode 100644 index 0000000..bf7fa1d Binary files /dev/null and b/examples/src/Jeep.png differ diff --git a/examples/src/RaycastCar.elm b/examples/src/RaycastCar.elm index 4cc0812..a3100c3 100644 --- a/examples/src/RaycastCar.elm +++ b/examples/src/RaycastCar.elm @@ -1,19 +1,19 @@ module RaycastCar exposing (main) -{-| This is a complex example implementing raycast vehicle enspired by: +{-| This demo implements a smooth car simulation. - - bullet3: - - cannon.js: + - `RayCastCar.Car` — raycast vehicle simulation algorithm, + - `RayCastCar.Jeep` — load the 3d model using elm-obj-file. -This is a car with fake wheels, that shoots rays and applies -impulses to the car body where the rays hit the ground. +Press arrow keys to drive, "b" to brake. -This allows to simulate suspension and results in smooth behavior. +Try to add more obstacles to the demo by changing the initialWorld, +or tweak the settings in the `RayCastCar.Jeep` module! -} import Acceleration -import Angle exposing (Angle) +import Angle import Axis3d import Block3d exposing (Block3d) import Browser @@ -21,23 +21,23 @@ import Browser.Dom import Browser.Events import Camera3d exposing (Camera3d) import Color -import Cylinder3d -import Direction3d exposing (Direction3d) -import Duration exposing (Duration) -import Force exposing (Force) -import Frame3d exposing (Frame3d) +import Direction3d +import Duration +import Frame3d import Html exposing (Html) import Html.Attributes import Json.Decode -import Length exposing (Length, Meters) +import Length exposing (Meters) import Mass import Physics.Body as Body exposing (Body) import Physics.Coordinates exposing (BodyCoordinates, WorldCoordinates) -import Physics.Material as Material import Physics.World as World exposing (World) import Pixels exposing (Pixels) +import Plane3d import Point3d exposing (Point3d) -import Quantity exposing (Quantity(..)) +import Quantity exposing (Quantity) +import RaycastCar.Car as Car exposing (Wheel) +import RaycastCar.Jeep as Jeep exposing (Jeep) import Scene3d exposing (Entity) import Scene3d.Material import Task @@ -48,122 +48,32 @@ import Viewpoint3d type Id = Obstacle (Block3d Meters BodyCoordinates) | Floor - | Car (List Wheel) - - -type alias CarSettings = - { downDirection : Direction3d BodyCoordinates - , rightDirection : Direction3d BodyCoordinates - , forwardDirection : Direction3d BodyCoordinates - , suspensionRestLength : Length - , minSuspensionLength : Length - , maxSuspensionLength : Length - , radius : Length - , suspensionStiffness : Float - , dampingCompression : Float - , dampingRelaxation : Float - , frictionSlip : Float - , rollInfluence : Float - , maxSuspensionForce : Force - } - - -carSettings : CarSettings -carSettings = - { downDirection = Direction3d.negativeZ - , rightDirection = Direction3d.y - , forwardDirection = Direction3d.x - , suspensionRestLength = Length.meters 0.3 - , minSuspensionLength = Length.meters 0 - , maxSuspensionLength = Length.meters 0.6 - , radius = Length.meters 0.5 - , suspensionStiffness = 30 - , dampingCompression = 4.4 - , dampingRelaxation = 2.3 - , frictionSlip = 5 - , rollInfluence = 0.01 - , maxSuspensionForce = Force.newtons 100000 - } - - -type alias Wheel = - { chassisConnectionPoint : Point3d Meters BodyCoordinates - , steering : Angle - , rotation : Angle - , deltaRotation : Angle - , suspensionImpulse : Quantity Float (Quantity.Product Force.Newtons Duration.Seconds) - , suspensionLength : Length - , engineForce : Force - , brake : Force - , contact : - Maybe - { point : Point3d Meters WorldCoordinates - , normal : Direction3d WorldCoordinates - , body : Body Id - } - } - - -defaultWheel : Wheel -defaultWheel = - { chassisConnectionPoint = Point3d.origin -- set for different wheels - , steering = Quantity.zero - , rotation = Quantity.zero - , deltaRotation = Quantity.zero - , suspensionImpulse = Quantity.zero - , suspensionLength = Quantity.zero - , engineForce = Quantity.zero - , brake = Quantity.zero - , contact = Nothing - } + | Car (List (Wheel Id)) type alias Model = - { world : World Id - , dimensions : ( Quantity Int Pixels, Quantity Int Pixels ) + { dimensions : ( Quantity Int Pixels, Quantity Int Pixels ) + , world : World Id + , jeep : Maybe Jeep + , firstTick : Bool , speeding : Float , steering : Float , braking : Bool } -type Command - = Speed Float - | Steer Float - | Brake - - -keyDecoder : (Command -> Msg) -> Json.Decode.Decoder Msg -keyDecoder toMsg = - Json.Decode.field "key" Json.Decode.string - |> Json.Decode.andThen - (\string -> - case string of - "ArrowLeft" -> - Json.Decode.succeed (toMsg (Steer -1)) - - "ArrowRight" -> - Json.Decode.succeed (toMsg (Steer 1)) - - "ArrowUp" -> - Json.Decode.succeed (toMsg (Speed 1)) - - "ArrowDown" -> - Json.Decode.succeed (toMsg (Speed -1)) - - "b" -> - Json.Decode.succeed (toMsg Brake) - - _ -> - Json.Decode.fail ("Unrecognized key: " ++ string) - ) - - type Msg = Tick | Resize Int Int | KeyDown Command | KeyUp Command + | JeepLoaded (Result String Jeep) + + +type Command + = Speed Float + | Steer Float + | Brake main : Program () Model Msg @@ -178,37 +88,98 @@ main = init : () -> ( Model, Cmd Msg ) init _ = - ( { world = initialWorld + ( { dimensions = ( Pixels.int 0, Pixels.int 0 ) + , world = initialWorld + , jeep = Nothing + , firstTick = True , speeding = 0 , steering = 0 - , dimensions = ( Pixels.int 0, Pixels.int 0 ) , braking = False } - , Task.perform - (\{ viewport } -> - Resize (round viewport.width) (round viewport.height) - ) - Browser.Dom.getViewport + , Cmd.batch + [ Task.perform + (\{ viewport } -> + Resize (round viewport.width) (round viewport.height) + ) + Browser.Dom.getViewport + , Jeep.load { texture = "Jeep.png", mesh = "Jeep.obj.txt" } |> Task.attempt JeepLoaded + ] ) +subscriptions : Model -> Sub Msg +subscriptions _ = + Sub.batch + [ Browser.Events.onResize Resize + , Browser.Events.onAnimationFrameDelta (always Tick) + , Browser.Events.onKeyDown (keyDecoder KeyDown) + , Browser.Events.onKeyUp (keyDecoder KeyUp) + ] + + update : Msg -> Model -> Model update msg model = case msg of + JeepLoaded result -> + case result of + Ok jeep -> + { model + | jeep = Just jeep + , world = + World.add + (Body.compound jeep.collider (Car (Jeep.wheels jeep)) + |> Body.withBehavior (Body.dynamic (Mass.kilograms 4000)) + |> Body.moveTo (Point3d.meters 0 0 6) + ) + model.world + } + + _ -> + model + Tick -> { model | world = - model.world - |> World.update - (\body -> - case Body.data body of - Car wheels -> - simulateCar (Duration.seconds (1 / 60)) model wheels body - - _ -> - body - ) - |> World.simulate (Duration.seconds (1 / 60)) + case model.jeep of + Just jeep -> + model.world + |> World.update + (\body -> + case Body.data body of + Car wheels -> + let + ( newBody, newWheels ) = + Car.simulate + (Jeep.settings jeep) + (Duration.seconds (1 / 60)) + { worldWithoutCar = + World.keepIf + (\b -> + case Body.data b of + Car _ -> + False + + _ -> + True + ) + model.world + , speeding = model.speeding + , steering = model.steering + , braking = model.braking + } + wheels + body + in + Body.withData (Car newWheels) newBody + + _ -> + body + ) + |> World.simulate (Duration.seconds (1 / 60)) + + _ -> + model.world + , firstTick = False } Resize width height -> @@ -247,31 +218,8 @@ update msg model = { model | braking = False } -subscriptions : Model -> Sub Msg -subscriptions _ = - Sub.batch - [ Browser.Events.onResize Resize - , Browser.Events.onAnimationFrameDelta (always Tick) - , Browser.Events.onKeyDown (keyDecoder KeyDown) - , Browser.Events.onKeyUp (keyDecoder KeyUp) - ] - - -camera : Camera3d Meters WorldCoordinates -camera = - Camera3d.perspective - { viewpoint = - Viewpoint3d.lookAt - { eyePoint = Point3d.meters -40 40 30 - , focalPoint = Point3d.meters 0 -7 0 - , upDirection = Direction3d.positiveZ - } - , verticalFieldOfView = Angle.degrees 24 - } - - view : Model -> Html Msg -view { world, dimensions } = +view { world, jeep, dimensions } = Html.div [ Html.Attributes.style "position" "absolute" , Html.Attributes.style "left" "0" @@ -279,19 +227,32 @@ view { world, dimensions } = ] [ Scene3d.sunny { upDirection = Direction3d.z - , sunlightDirection = Direction3d.xyZ (Angle.degrees 135) (Angle.degrees -60) + , sunlightDirection = Direction3d.xyZ (Angle.degrees -15) (Angle.degrees -45) , shadows = True , camera = camera , dimensions = dimensions , background = Scene3d.transparentBackground , clipDepth = Length.meters 0.1 - , entities = List.map bodyToEntity (World.bodies world) + , entities = List.map (bodyToEntity jeep) (World.bodies world) } ] -bodyToEntity : Body Id -> Entity WorldCoordinates -bodyToEntity body = +camera : Camera3d Meters WorldCoordinates +camera = + Camera3d.perspective + { viewpoint = + Viewpoint3d.lookAt + { eyePoint = Point3d.meters -40 40 30 + , focalPoint = Point3d.meters 0 -7 0 + , upDirection = Direction3d.positiveZ + } + , verticalFieldOfView = Angle.degrees 24 + } + + +bodyToEntity : Maybe Jeep -> Body Id -> Entity WorldCoordinates +bodyToEntity maybeJeep body = let id = Body.data body @@ -302,7 +263,7 @@ bodyToEntity body = Scene3d.placeIn frame <| case id of Floor -> - Scene3d.quad (Scene3d.Material.matte Color.darkCharcoal) + Scene3d.quad (Scene3d.Material.matte Color.white) (Point3d.meters -100 -100 0) (Point3d.meters -100 100 0) (Point3d.meters 100 100 0) @@ -311,58 +272,61 @@ bodyToEntity body = Obstacle block -> Scene3d.blockWithShadow (Scene3d.Material.nonmetal - { baseColor = Color.white - , roughness = 0.25 + { baseColor = Color.lightGray + , roughness = 1 } ) block Car wheels -> - Scene3d.group - (List.foldl - (\wheel entities -> - let - position = - wheel.chassisConnectionPoint - - downDirection = - carSettings.downDirection - - rightDirection = - carSettings.rightDirection - - newPosition = - position |> Point3d.translateBy (Vector3d.withLength wheel.suspensionLength downDirection) - - newFrame = - Frame3d.atOrigin - |> Frame3d.moveTo newPosition - |> Frame3d.rotateAround (Axis3d.through newPosition rightDirection) wheel.rotation - |> Frame3d.rotateAround (Axis3d.through newPosition downDirection) wheel.steering - in - Scene3d.cylinderWithShadow - (Scene3d.Material.nonmetal - { baseColor = Color.white - , roughness = 0.25 - } + case maybeJeep of + Just jeep -> + Scene3d.group + (List.foldl + (\wheel entities -> + let + position = + wheel.chassisConnectionPoint + + { downDirection, rightDirection } = + Jeep.settings jeep + + axisDirection = + Axis3d.direction wheel.axis + + angle = + if Quantity.greaterThan Quantity.zero (Direction3d.angleFrom rightDirection axisDirection) then + identity + + else + Frame3d.mirrorAcross Plane3d.yz + + newPosition = + position |> Point3d.translateBy (Vector3d.withLength wheel.suspensionLength downDirection) + + newFrame = + Frame3d.atOrigin + |> angle + |> Frame3d.rotateAround (Axis3d.through Point3d.origin (Direction3d.reverse rightDirection)) wheel.rotation + |> Frame3d.rotateAround (Axis3d.through Point3d.origin downDirection) wheel.steering + |> Frame3d.moveTo newPosition + in + (Scene3d.meshWithShadow jeep.material + jeep.wheel + jeep.wheelShadow + |> Scene3d.placeIn newFrame + ) + :: entities ) - (Cylinder3d.centeredOn Point3d.origin - Direction3d.y - { radius = carSettings.radius, length = Length.meters 0.2 } - |> Cylinder3d.placeIn newFrame - ) - :: entities - ) - [ Scene3d.blockWithShadow - (Scene3d.Material.nonmetal - { baseColor = Color.white - , roughness = 0.25 - } + [ Scene3d.meshWithShadow jeep.material + jeep.chassis + jeep.chassisShadow + ] + wheels ) - carBlock - ] - wheels - ) + + Nothing -> + Scene3d.nothing initialWorld : World Id @@ -377,484 +341,6 @@ initialWorld = |> World.add (box (Point3d.meters 15 -16 1.5)) |> World.add (box (Point3d.meters 15 -17.5 1.5)) |> World.add (box (Point3d.meters 15 -16.5 2.5)) - |> World.add (Body.moveTo (Point3d.meters 0 0 6) car) - - -simulateCar : Duration -> Model -> List Wheel -> Body Id -> Body Id -simulateCar dt { world, steering, braking, speeding } wheels carBody = - case wheels of - [ w1, w2, w3, w4 ] -> - let - engineForce = - Force.newtons (500 * speeding) - - brake = - if braking then - Force.newtons 1000 - - else - Quantity.zero - - wheel1 = - { w1 | steering = Angle.degrees (30 * steering), engineForce = engineForce, brake = brake } - - wheel2 = - { w2 | steering = Angle.degrees (30 * steering), engineForce = engineForce, brake = brake } - - wheel3 = - { w3 | engineForce = engineForce, brake = brake } - - wheel4 = - { w4 | engineForce = engineForce, brake = brake } - in - updateSuspension dt world (Body.frame carBody) carBody [ wheel1, wheel2, wheel3, wheel4 ] carBody [] 0 - - _ -> - carBody - - -updateSuspension : Duration -> World Id -> Frame3d Meters WorldCoordinates { defines : BodyCoordinates } -> Body Id -> List Wheel -> Body Id -> List Wheel -> Int -> Body Id -updateSuspension dt world frame originalCar currentWheels updatedCar updatedWheels numWheelsOnGround = - case currentWheels of - [] -> - updateFriction dt world frame updatedCar numWheelsOnGround updatedWheels [] [] False - - wheel :: remainingWheels -> - let - ray = - Axis3d.through wheel.chassisConnectionPoint carSettings.downDirection - |> Axis3d.placeIn frame - - collidesWithWheels body = - case Body.data body of - Floor -> - True - - Obstacle _ -> - True - - Car _ -> - False - in - case World.raycast ray (World.keepIf collidesWithWheels world) of - Just { body, normal, point } -> - let - bodyFrame = - Body.frame body - - contactPoint = - Point3d.placeIn bodyFrame point - - contactNormal = - Direction3d.placeIn bodyFrame normal - - distance = - Point3d.distanceFrom contactPoint (Axis3d.originPoint ray) - - maxDistance = - Quantity.plus carSettings.suspensionRestLength carSettings.radius - in - if Quantity.lessThan maxDistance distance then - let - suspensionLength = - distance - |> Quantity.minus carSettings.radius - |> Quantity.clamp - carSettings.minSuspensionLength - carSettings.maxSuspensionLength - - difference = - carSettings.suspensionRestLength - |> Quantity.minus suspensionLength - |> Length.inMeters - - (Quantity projectedVelocity) = - Vector3d.dot - (Direction3d.toVector contactNormal) - (Body.velocityAt contactPoint originalCar) - - (Quantity denominator) = - Vector3d.dot - (Direction3d.toVector contactNormal) - (Direction3d.toVector (Axis3d.direction ray)) - - ( suspensionRelativeVelocity, clippedInvContactDotSuspension ) = - if denominator >= -0.1 then - ( 0, 1 / 0.1 ) - - else - ( -projectedVelocity / denominator, -1 / denominator ) - - damping = - if suspensionRelativeVelocity < 0 then - carSettings.dampingCompression - - else - carSettings.dampingRelaxation - - suspensionImpulse = - ((carSettings.suspensionStiffness * difference * clippedInvContactDotSuspension) - - (damping * suspensionRelativeVelocity) - ) - |> (*) (Body.mass originalCar |> Maybe.map Mass.inKilograms |> Maybe.withDefault 0) - |> Force.newtons - |> Quantity.clamp Quantity.zero carSettings.maxSuspensionForce - |> Quantity.times dt - in - updateSuspension dt - world - frame - originalCar - remainingWheels - (Body.applyImpulse - suspensionImpulse - contactNormal - contactPoint - updatedCar - ) - ({ wheel - | contact = - Just - { point = contactPoint - , normal = contactNormal - , body = body - } - , suspensionLength = suspensionLength - , suspensionImpulse = suspensionImpulse - } - :: updatedWheels - ) - (numWheelsOnGround + 1) - - else - updateSuspension dt - world - frame - originalCar - remainingWheels - updatedCar - ({ wheel - | contact = Nothing - , suspensionLength = carSettings.suspensionRestLength - } - :: updatedWheels - ) - numWheelsOnGround - - Nothing -> - updateSuspension dt - world - frame - originalCar - remainingWheels - updatedCar - ({ wheel - | contact = Nothing - , suspensionLength = carSettings.suspensionRestLength - } - :: updatedWheels - ) - numWheelsOnGround - - -type alias WheelFriction = - { forward : Direction3d WorldCoordinates - , axle : Direction3d WorldCoordinates - , sideImpulse : Quantity Float (Quantity.Product Force.Newtons Duration.Seconds) - , forwardImpulse : Quantity Float (Quantity.Product Force.Newtons Duration.Seconds) - , skidInfo : Float - , contactPoint : Point3d Meters WorldCoordinates - , contactBody : Body Id - } - - -updateFriction : Duration -> World Id -> Frame3d Meters WorldCoordinates { defines : BodyCoordinates } -> Body Id -> Int -> List Wheel -> List WheelFriction -> List Wheel -> Bool -> Body Id -updateFriction dt world frame updatedCar numWheelsOnGround currentWheels wheelFrictions updatedWheels sliding = - case currentWheels of - [] -> - applyImpulses dt world frame updatedCar updatedWheels sliding wheelFrictions - - wheel :: remainingWheels -> - case wheel.contact of - Just { point, normal, body } -> - let - worldAxle = - carSettings.rightDirection - |> Direction3d.rotateAround (Axis3d.through wheel.chassisConnectionPoint carSettings.downDirection) wheel.steering - |> Direction3d.placeIn frame - - (Quantity proj) = - Vector3d.dot (Direction3d.toVector normal) (Direction3d.toVector worldAxle) - - axle = - Direction3d.toVector worldAxle - |> Vector3d.minus (Vector3d.scaleBy proj (Direction3d.toVector normal)) - |> Vector3d.direction - |> Maybe.withDefault normal - - forward = - Vector3d.cross (Direction3d.toVector normal) (Direction3d.toVector axle) - |> Vector3d.direction - |> Maybe.withDefault normal - - sideImpulse = - resolveSingleBilateral updatedCar body point axle - - maxImpulse = - if wheel.brake == Quantity.zero then - -- TODO: think about default rolling friction impulse - Quantity.zero - - else - Quantity.times dt wheel.brake - - forwardImpulse = - Quantity.times dt wheel.engineForce - |> Quantity.plus (calcRollingFriction updatedCar body point forward maxImpulse numWheelsOnGround) - - -- Switch between active rolling (throttle), braking and non-active rolling friction (nthrottle/break) - maximpSide = - Quantity.multiplyBy carSettings.frictionSlip wheel.suspensionImpulse - - impulseSquared = - Quantity.times forwardImpulse forwardImpulse - |> Quantity.multiplyBy 0.25 - |> Quantity.plus (Quantity.times sideImpulse sideImpulse) - - isSliding = - Quantity.greaterThan (Quantity.times maximpSide maximpSide) impulseSquared - - skidInfo = - if isSliding then - Quantity.ratio maximpSide (Quantity.sqrt impulseSquared) - - else - 1 - in - updateFriction - dt - world - frame - updatedCar - numWheelsOnGround - remainingWheels - ({ forward = forward - , axle = axle - , sideImpulse = sideImpulse - , forwardImpulse = forwardImpulse - , skidInfo = skidInfo - , contactPoint = point - , contactBody = body - } - :: wheelFrictions - ) - (wheel :: updatedWheels) - (sliding || isSliding) - - Nothing -> - updateFriction - dt - world - frame - updatedCar - numWheelsOnGround - remainingWheels - wheelFrictions - (wheel :: updatedWheels) - sliding - - -applyImpulses : Duration -> World Id -> Frame3d Meters WorldCoordinates { defines : BodyCoordinates } -> Body Id -> List Wheel -> Bool -> List WheelFriction -> Body Id -applyImpulses dt world frame carBody wheels sliding wheelFrictions = - case wheelFrictions of - [] -> - rotateWheels dt frame carBody wheels [] - - friction :: remainingFrictions -> - let - centerOfMass = - Body.centerOfMass carBody - |> Point3d.placeIn frame - - up = - Direction3d.reverse carSettings.downDirection - |> Direction3d.placeIn frame - - verticalDistance = - Vector3d.from friction.contactPoint centerOfMass - |> Vector3d.componentIn up - |> Quantity.multiplyBy (1 - carSettings.rollInfluence) - - closerToCenterOfMass = - Point3d.translateIn up verticalDistance friction.contactPoint - - forwardImpulse = - if sliding then - Quantity.multiplyBy friction.skidInfo friction.forwardImpulse - - else - friction.forwardImpulse - - sideImpulse = - if sliding then - Quantity.multiplyBy friction.skidInfo friction.sideImpulse - - else - friction.sideImpulse - - newCar = - carBody - |> Body.applyImpulse forwardImpulse friction.forward friction.contactPoint - |> Body.applyImpulse sideImpulse friction.axle closerToCenterOfMass - - -- TODO: apply the reverse of the sideImpulse on the ground object too, for now assume it is static - in - applyImpulses - dt - world - frame - newCar - wheels - sliding - remainingFrictions - - -rotateWheels : Duration -> Frame3d Meters WorldCoordinates { defines : BodyCoordinates } -> Body Id -> List Wheel -> List Wheel -> Body Id -rotateWheels dt frame carBody wheels updatedWheels = - case wheels of - [] -> - Body.withData - (Car (List.reverse updatedWheels)) - carBody - - wheel :: remainingWheels -> - case wheel.contact of - Just { point, normal } -> - let - velocity = - Body.velocityAt point carBody - - forward = - Direction3d.placeIn frame carSettings.forwardDirection - - proj = - Direction3d.componentIn normal forward - - (Quantity proj2) = - forward - |> Direction3d.toVector - |> Vector3d.minus (Vector3d.withLength (Quantity proj) normal) - |> Vector3d.dot velocity - - deltaRotation = - Quantity (proj2 * Duration.inSeconds dt / Length.inMeters carSettings.radius) - - newWheel = - { wheel - | deltaRotation = deltaRotation - , rotation = Quantity.plus wheel.rotation wheel.deltaRotation - } - in - rotateWheels dt frame carBody remainingWheels (newWheel :: updatedWheels) - - Nothing -> - let - deltaRotation = - Quantity.multiplyBy 0.99 wheel.deltaRotation - - newWheel = - { wheel - -- damping when not in contact - | deltaRotation = Quantity.multiplyBy 0.99 wheel.deltaRotation - , rotation = Quantity.plus wheel.rotation deltaRotation - } - in - rotateWheels dt frame carBody remainingWheels (newWheel :: updatedWheels) - - -resolveSingleBilateral : Body Id -> Body Id -> Point3d Meters WorldCoordinates -> Direction3d WorldCoordinates -> Quantity Float (Quantity.Product Force.Newtons Duration.Seconds) -resolveSingleBilateral body1 body2 point direction = - let - velocity1 = - Body.velocityAt point body1 - - velocity2 = - Body.velocityAt point body2 - - (Quantity relativeVelocity) = - Vector3d.dot (Vector3d.minus velocity2 velocity1) (Direction3d.toVector direction) - - contactDamping = - 0.2 - - invMass1 = - case Body.mass body1 of - Just mass -> - 1 / Mass.inKilograms mass - - Nothing -> - 0 - - invMass2 = - case Body.mass body2 of - Just mass -> - 1 / Mass.inKilograms mass - - Nothing -> - 0 - - massTerm = - 1 / (invMass1 + invMass2) - in - Quantity (-contactDamping * relativeVelocity * massTerm) - - -calcRollingFriction : Body Id -> Body Id -> Point3d Meters WorldCoordinates -> Direction3d WorldCoordinates -> Quantity Float (Quantity.Product Force.Newtons Duration.Seconds) -> Int -> Quantity Float (Quantity.Product Force.Newtons Duration.Seconds) -calcRollingFriction body1 body2 point forward maxImpulse numWheelsOnGround = - let - velocity1 = - Body.velocityAt point body1 - - velocity2 = - Body.velocityAt point body2 - - (Quantity relativeVelocity) = - Vector3d.dot (Vector3d.minus velocity2 velocity1) (Direction3d.toVector forward) - - denom1 = - computeImpulseDenominator body1 point forward - - denom2 = - computeImpulseDenominator body2 point forward - in - Quantity (-relativeVelocity / (denom1 + denom2) / toFloat numWheelsOnGround) - |> Quantity.clamp (Quantity.negate maxImpulse) maxImpulse - - -computeImpulseDenominator : Body Id -> Point3d Meters WorldCoordinates -> Direction3d WorldCoordinates -> Float -computeImpulseDenominator body point normal = - let - position = - Point3d.placeIn (Body.frame body) (Body.centerOfMass body) - - r0 = - Vector3d.from position point - - c0 = - Vector3d.cross r0 (Direction3d.toVector normal) - - vec = - Vector3d.cross (Body.transformWithInverseInertia body c0) r0 - - (Quantity dot) = - Vector3d.dot (Direction3d.toVector normal) vec - in - case Body.mass body of - Just mass -> - 1 / Mass.inKilograms mass + dot - - Nothing -> - dot {-| A slope to give a car the initial push. @@ -889,29 +375,27 @@ box position = |> Body.moveTo position -carBlock : Block3d Meters BodyCoordinates -carBlock = - Block3d.centeredOn Frame3d.atOrigin - ( Length.meters 4 - , Length.meters 2 - , Length.meters 1 - ) +keyDecoder : (Command -> Msg) -> Json.Decode.Decoder Msg +keyDecoder toMsg = + Json.Decode.field "key" Json.Decode.string + |> Json.Decode.andThen + (\string -> + case string of + "ArrowLeft" -> + Json.Decode.succeed (toMsg (Steer -1)) + "ArrowRight" -> + Json.Decode.succeed (toMsg (Steer 1)) -car : Body Id -car = - let - wheels = - [ { defaultWheel | chassisConnectionPoint = Point3d.meters 1 1 0 } - , { defaultWheel | chassisConnectionPoint = Point3d.meters 1 -1 0 } - , { defaultWheel | chassisConnectionPoint = Point3d.meters -1 1 0 } - , { defaultWheel | chassisConnectionPoint = Point3d.meters -1 -1 0 } - ] - - -- We don't want the car to stuck when bumping into the obstacles - slippy = - Material.custom { friction = -1, bounciness = 0.6 } - in - Body.block carBlock (Car wheels) - |> Body.withBehavior (Body.dynamic (Mass.kilograms 150)) - |> Body.withMaterial slippy + "ArrowUp" -> + Json.Decode.succeed (toMsg (Speed 1)) + + "ArrowDown" -> + Json.Decode.succeed (toMsg (Speed -1)) + + "b" -> + Json.Decode.succeed (toMsg Brake) + + _ -> + Json.Decode.fail ("Unrecognized key: " ++ string) + ) diff --git a/examples/src/RaycastCar/Car.elm b/examples/src/RaycastCar/Car.elm new file mode 100644 index 0000000..0993c72 --- /dev/null +++ b/examples/src/RaycastCar/Car.elm @@ -0,0 +1,557 @@ +module RaycastCar.Car exposing (CarSettings, Wheel, defaultWheel, simulate) + +{-| This is a complex example implementing raycast vehicle enspired by: + + - bullet3: + - cannon.js: + +This is a car with fake wheels, that shoots rays and applies +impulses to the car body where the rays hit the ground. + +This allows to simulate suspension and results in smooth behavior. + +-} + +import Angle exposing (Angle) +import Axis3d exposing (Axis3d) +import Direction3d exposing (Direction3d) +import Duration exposing (Duration) +import Force exposing (Force) +import Frame3d exposing (Frame3d) +import Length exposing (Length, Meters) +import Mass +import Physics.Body as Body exposing (Body) +import Physics.Coordinates exposing (BodyCoordinates, WorldCoordinates) +import Physics.World as World exposing (World) +import Point3d exposing (Point3d) +import Quantity exposing (Quantity(..)) +import Vector3d + + +type alias CarSettings = + { downDirection : Direction3d BodyCoordinates + , rightDirection : Direction3d BodyCoordinates + , forwardDirection : Direction3d BodyCoordinates + , suspensionRestLength : Length + , minSuspensionLength : Length + , maxSuspensionLength : Length + , radius : Length + , suspensionStiffness : Float + , dampingCompression : Float + , dampingRelaxation : Float + , frictionSlip : Float + , rollInfluence : Float + , maxSuspensionForce : Force + } + + +type alias Wheel id = + { chassisConnectionPoint : Point3d Meters BodyCoordinates + , axis : Axis3d Meters BodyCoordinates + , steering : Angle + , rotation : Angle + , deltaRotation : Angle + , suspensionImpulse : Quantity Float (Quantity.Product Force.Newtons Duration.Seconds) + , suspensionLength : Length + , engineForce : Force + , brake : Force + , contact : + Maybe + { point : Point3d Meters WorldCoordinates + , normal : Direction3d WorldCoordinates + , body : Body id + } + } + + +simulate : + CarSettings + -> Duration + -> + { worldWithoutCar : World id + , speeding : Float + , steering : Float + , braking : Bool + } + -> List (Wheel id) + -> Body id + -> ( Body id, List (Wheel id) ) +simulate carSettings dt { worldWithoutCar, steering, braking, speeding } wheels carBody = + case wheels of + [ w1, w2, w3, w4 ] -> + let + engineForce = + Force.newtons (5000 * speeding) + + brake = + if braking then + Force.newtons 10000 + + else + Quantity.zero + + wheel1 = + { w1 | steering = Angle.degrees (30 * steering), engineForce = engineForce, brake = brake } + + wheel2 = + { w2 | steering = Angle.degrees (30 * steering), engineForce = engineForce, brake = brake } + + wheel3 = + { w3 | engineForce = engineForce, brake = brake } + + wheel4 = + { w4 | engineForce = engineForce, brake = brake } + in + updateSuspension carSettings dt worldWithoutCar (Body.frame carBody) carBody [ wheel1, wheel2, wheel3, wheel4 ] carBody [] 0 + + _ -> + ( carBody, wheels ) + + +updateSuspension : CarSettings -> Duration -> World id -> Frame3d Meters WorldCoordinates { defines : BodyCoordinates } -> Body id -> List (Wheel id) -> Body id -> List (Wheel id) -> Int -> ( Body id, List (Wheel id) ) +updateSuspension carSettings dt world frame originalCar currentWheels updatedCar updatedWheels numWheelsOnGround = + case currentWheels of + [] -> + updateFriction carSettings dt world frame updatedCar numWheelsOnGround updatedWheels [] [] False + + wheel :: remainingWheels -> + let + ray = + Axis3d.through wheel.chassisConnectionPoint carSettings.downDirection + |> Axis3d.placeIn frame + in + case World.raycast ray world of + Just { body, normal, point } -> + let + bodyFrame = + Body.frame body + + contactPoint = + Point3d.placeIn bodyFrame point + + contactNormal = + Direction3d.placeIn bodyFrame normal + + distance = + Point3d.distanceFrom contactPoint (Axis3d.originPoint ray) + + maxDistance = + Quantity.plus carSettings.suspensionRestLength carSettings.radius + in + if Quantity.lessThan maxDistance distance then + let + suspensionLength = + distance + |> Quantity.minus carSettings.radius + |> Quantity.clamp + carSettings.minSuspensionLength + carSettings.maxSuspensionLength + + difference = + carSettings.suspensionRestLength + |> Quantity.minus suspensionLength + |> Length.inMeters + + (Quantity projectedVelocity) = + Vector3d.dot + (Direction3d.toVector contactNormal) + (Body.velocityAt contactPoint originalCar) + + (Quantity denominator) = + Vector3d.dot + (Direction3d.toVector contactNormal) + (Direction3d.toVector (Axis3d.direction ray)) + + ( suspensionRelativeVelocity, clippedInvContactDotSuspension ) = + if denominator >= -0.1 then + ( 0, 1 / 0.1 ) + + else + ( -projectedVelocity / denominator, -1 / denominator ) + + damping = + if suspensionRelativeVelocity < 0 then + carSettings.dampingCompression + + else + carSettings.dampingRelaxation + + suspensionImpulse = + ((carSettings.suspensionStiffness * difference * clippedInvContactDotSuspension) + - (damping * suspensionRelativeVelocity) + ) + |> (*) (Body.mass originalCar |> Maybe.map Mass.inKilograms |> Maybe.withDefault 0) + |> Force.newtons + |> Quantity.clamp Quantity.zero carSettings.maxSuspensionForce + |> Quantity.times dt + in + updateSuspension carSettings + dt + world + frame + originalCar + remainingWheels + (Body.applyImpulse + suspensionImpulse + contactNormal + contactPoint + updatedCar + ) + ({ wheel + | contact = + Just + { point = contactPoint + , normal = contactNormal + , body = body + } + , suspensionLength = suspensionLength + , suspensionImpulse = suspensionImpulse + } + :: updatedWheels + ) + (numWheelsOnGround + 1) + + else + updateSuspension carSettings + dt + world + frame + originalCar + remainingWheels + updatedCar + ({ wheel + | contact = Nothing + , suspensionLength = carSettings.suspensionRestLength + } + :: updatedWheels + ) + numWheelsOnGround + + Nothing -> + updateSuspension carSettings + dt + world + frame + originalCar + remainingWheels + updatedCar + ({ wheel + | contact = Nothing + , suspensionLength = carSettings.suspensionRestLength + } + :: updatedWheels + ) + numWheelsOnGround + + +type alias WheelFriction id = + { forward : Direction3d WorldCoordinates + , axle : Direction3d WorldCoordinates + , sideImpulse : Quantity Float (Quantity.Product Force.Newtons Duration.Seconds) + , forwardImpulse : Quantity Float (Quantity.Product Force.Newtons Duration.Seconds) + , skidInfo : Float + , contactPoint : Point3d Meters WorldCoordinates + , contactBody : Body id + } + + +updateFriction : CarSettings -> Duration -> World id -> Frame3d Meters WorldCoordinates { defines : BodyCoordinates } -> Body id -> Int -> List (Wheel id) -> List (WheelFriction id) -> List (Wheel id) -> Bool -> ( Body id, List (Wheel id) ) +updateFriction carSettings dt world frame updatedCar numWheelsOnGround currentWheels wheelFrictions updatedWheels sliding = + case currentWheels of + [] -> + applyImpulses carSettings dt world frame updatedCar updatedWheels sliding wheelFrictions + + wheel :: remainingWheels -> + case wheel.contact of + Just { point, normal, body } -> + let + worldAxle = + carSettings.rightDirection + |> Direction3d.rotateAround (Axis3d.through wheel.chassisConnectionPoint carSettings.downDirection) wheel.steering + |> Direction3d.placeIn frame + + (Quantity proj) = + Vector3d.dot (Direction3d.toVector normal) (Direction3d.toVector worldAxle) + + axle = + Direction3d.toVector worldAxle + |> Vector3d.minus (Vector3d.scaleBy proj (Direction3d.toVector normal)) + |> Vector3d.direction + |> Maybe.withDefault normal + + forward = + Vector3d.cross (Direction3d.toVector normal) (Direction3d.toVector axle) + |> Vector3d.direction + |> Maybe.withDefault normal + + sideImpulse = + resolveSingleBilateral updatedCar body point axle + + maxImpulse = + if wheel.brake == Quantity.zero then + -- TODO: think about default rolling friction impulse + Quantity.zero + + else + Quantity.times dt wheel.brake + + forwardImpulse = + Quantity.times dt wheel.engineForce + |> Quantity.plus (calcRollingFriction updatedCar body point forward maxImpulse numWheelsOnGround) + + -- Switch between active rolling (throttle), braking and non-active rolling friction (nthrottle/break) + maximpSide = + Quantity.multiplyBy carSettings.frictionSlip wheel.suspensionImpulse + + impulseSquared = + Quantity.times forwardImpulse forwardImpulse + |> Quantity.multiplyBy 0.25 + |> Quantity.plus (Quantity.times sideImpulse sideImpulse) + + isSliding = + Quantity.greaterThan (Quantity.times maximpSide maximpSide) impulseSquared + + skidInfo = + if isSliding then + Quantity.ratio maximpSide (Quantity.sqrt impulseSquared) + + else + 1 + in + updateFriction carSettings + dt + world + frame + updatedCar + numWheelsOnGround + remainingWheels + ({ forward = forward + , axle = axle + , sideImpulse = sideImpulse + , forwardImpulse = forwardImpulse + , skidInfo = skidInfo + , contactPoint = point + , contactBody = body + } + :: wheelFrictions + ) + (wheel :: updatedWheels) + (sliding || isSliding) + + Nothing -> + updateFriction carSettings + dt + world + frame + updatedCar + numWheelsOnGround + remainingWheels + wheelFrictions + (wheel :: updatedWheels) + sliding + + +applyImpulses : CarSettings -> Duration -> World id -> Frame3d Meters WorldCoordinates { defines : BodyCoordinates } -> Body id -> List (Wheel id) -> Bool -> List (WheelFriction id) -> ( Body id, List (Wheel id) ) +applyImpulses carSettings dt world frame carBody wheels sliding wheelFrictions = + case wheelFrictions of + [] -> + rotateWheels carSettings dt frame carBody wheels [] + + friction :: remainingFrictions -> + let + centerOfMass = + Body.centerOfMass carBody + |> Point3d.placeIn frame + + up = + Direction3d.reverse carSettings.downDirection + |> Direction3d.placeIn frame + + verticalDistance = + Vector3d.from friction.contactPoint centerOfMass + |> Vector3d.componentIn up + |> Quantity.multiplyBy (1 - carSettings.rollInfluence) + + closerToCenterOfMass = + Point3d.translateIn up verticalDistance friction.contactPoint + + forwardImpulse = + if sliding then + Quantity.multiplyBy friction.skidInfo friction.forwardImpulse + + else + friction.forwardImpulse + + sideImpulse = + if sliding then + Quantity.multiplyBy friction.skidInfo friction.sideImpulse + + else + friction.sideImpulse + + newCar = + carBody + |> Body.applyImpulse forwardImpulse friction.forward friction.contactPoint + |> Body.applyImpulse sideImpulse friction.axle closerToCenterOfMass + + -- TODO: apply the reverse of the sideImpulse on the ground object too, for now assume it is static + in + applyImpulses carSettings + dt + world + frame + newCar + wheels + sliding + remainingFrictions + + +rotateWheels : CarSettings -> Duration -> Frame3d Meters WorldCoordinates { defines : BodyCoordinates } -> Body id -> List (Wheel id) -> List (Wheel id) -> ( Body id, List (Wheel id) ) +rotateWheels carSettings dt frame carBody wheels updatedWheels = + case wheels of + [] -> + ( carBody, List.reverse updatedWheels ) + + wheel :: remainingWheels -> + case wheel.contact of + Just { point, normal } -> + let + velocity = + Body.velocityAt point carBody + + forward = + Direction3d.placeIn frame carSettings.forwardDirection + + proj = + Direction3d.componentIn normal forward + + (Quantity proj2) = + forward + |> Direction3d.toVector + |> Vector3d.minus (Vector3d.withLength (Quantity proj) normal) + |> Vector3d.dot velocity + + deltaRotation = + Quantity (proj2 * Duration.inSeconds dt / Length.inMeters carSettings.radius) + + newWheel = + { wheel + | deltaRotation = deltaRotation + , rotation = Quantity.plus wheel.rotation wheel.deltaRotation + } + in + rotateWheels carSettings dt frame carBody remainingWheels (newWheel :: updatedWheels) + + Nothing -> + let + deltaRotation = + Quantity.multiplyBy 0.99 wheel.deltaRotation + + newWheel = + { wheel + -- damping when not in contact + | deltaRotation = Quantity.multiplyBy 0.99 wheel.deltaRotation + , rotation = Quantity.plus wheel.rotation deltaRotation + } + in + rotateWheels carSettings dt frame carBody remainingWheels (newWheel :: updatedWheels) + + +resolveSingleBilateral : Body id -> Body id -> Point3d Meters WorldCoordinates -> Direction3d WorldCoordinates -> Quantity Float (Quantity.Product Force.Newtons Duration.Seconds) +resolveSingleBilateral body1 body2 point direction = + let + velocity1 = + Body.velocityAt point body1 + + velocity2 = + Body.velocityAt point body2 + + (Quantity relativeVelocity) = + Vector3d.dot (Vector3d.minus velocity2 velocity1) (Direction3d.toVector direction) + + contactDamping = + 0.2 + + invMass1 = + case Body.mass body1 of + Just mass -> + 1 / Mass.inKilograms mass + + Nothing -> + 0 + + invMass2 = + case Body.mass body2 of + Just mass -> + 1 / Mass.inKilograms mass + + Nothing -> + 0 + + massTerm = + 1 / (invMass1 + invMass2) + in + Quantity (-contactDamping * relativeVelocity * massTerm) + + +calcRollingFriction : Body id -> Body id -> Point3d Meters WorldCoordinates -> Direction3d WorldCoordinates -> Quantity Float (Quantity.Product Force.Newtons Duration.Seconds) -> Int -> Quantity Float (Quantity.Product Force.Newtons Duration.Seconds) +calcRollingFriction body1 body2 point forward maxImpulse numWheelsOnGround = + let + velocity1 = + Body.velocityAt point body1 + + velocity2 = + Body.velocityAt point body2 + + (Quantity relativeVelocity) = + Vector3d.dot (Vector3d.minus velocity2 velocity1) (Direction3d.toVector forward) + + denom1 = + computeImpulseDenominator body1 point forward + + denom2 = + computeImpulseDenominator body2 point forward + in + Quantity (-relativeVelocity / (denom1 + denom2) / toFloat numWheelsOnGround) + |> Quantity.clamp (Quantity.negate maxImpulse) maxImpulse + + +computeImpulseDenominator : Body id -> Point3d Meters WorldCoordinates -> Direction3d WorldCoordinates -> Float +computeImpulseDenominator body point normal = + let + position = + Point3d.placeIn (Body.frame body) (Body.centerOfMass body) + + r0 = + Vector3d.from position point + + c0 = + Vector3d.cross r0 (Direction3d.toVector normal) + + vec = + Vector3d.cross (Body.transformWithInverseInertia body c0) r0 + + (Quantity dot) = + Vector3d.dot (Direction3d.toVector normal) vec + in + case Body.mass body of + Just mass -> + 1 / Mass.inKilograms mass + dot + + Nothing -> + dot + + +defaultWheel : Wheel id +defaultWheel = + { chassisConnectionPoint = Point3d.origin -- set for different wheels + , axis = Axis3d.x -- set for different wheels + , steering = Quantity.zero + , rotation = Quantity.zero + , deltaRotation = Quantity.zero + , suspensionImpulse = Quantity.zero + , suspensionLength = Quantity.zero + , engineForce = Quantity.zero + , brake = Quantity.zero + , contact = Nothing + } diff --git a/examples/src/RaycastCar/Jeep.elm b/examples/src/RaycastCar/Jeep.elm new file mode 100644 index 0000000..1a7b362 --- /dev/null +++ b/examples/src/RaycastCar/Jeep.elm @@ -0,0 +1,205 @@ +module RaycastCar.Jeep exposing (Jeep, load, settings, wheels) + +{-| elm-obj-file is used to decode various objects from the jeep model. + +Body of the car, used for elm-physics simulation: + + - `convex-base_Base` + - `convex-window_Window` + +Positions of the wheels: + + - `front-right_Axis3d` + - `rear-right_Axis3d` + - `front-left_Axis3d` + - `rear-left_Axis3d` + +Used for rendering: + + - `chassis_Chassis` + - `chassis-fender-left_fender-left` + - `chassis-fender-right_fender-right` + - `chassis-bumper_Bumper` + - `chassis-cannister_Cannister` + - `chassis-lamp-left_lamp-left` + - `chassis-lamp-right_lamp-right` + - `chassis-spare_Wheel` + +Wheel, positioned at the origin: + + - `Wheel` + +The Jeep model is courtesy of Kolja Wilcke + +-} + +import Array +import Axis3d exposing (Axis3d) +import BoundingBox3d +import Direction3d +import Force +import Frame3d +import Http +import Length exposing (Length, Meters) +import Obj.Decode exposing (Decoder) +import Physics.Coordinates exposing (BodyCoordinates) +import Physics.Shape as Shape exposing (Shape) +import Point3d +import Polyline3d +import Quantity +import RaycastCar.Car exposing (CarSettings, Wheel, defaultWheel) +import Scene3d.Material +import Scene3d.Mesh exposing (Shadow, Textured) +import Task exposing (Task) +import TriangularMesh + + +type alias Jeep = + { collider : List Shape + , chassis : Textured BodyCoordinates + , chassisShadow : Shadow BodyCoordinates + , wheel : Textured BodyCoordinates + , wheelRadius : Length + , wheelWidth : Length + , wheelShadow : Shadow BodyCoordinates + , wheelAxes : List (Axis3d Meters BodyCoordinates) + , material : Scene3d.Material.Textured BodyCoordinates + } + + +load : { texture : String, mesh : String } -> Task String Jeep +load urls = + Http.task + { method = "get" + , headers = [] + , body = Http.emptyBody + , url = urls.mesh + , resolver = + Http.stringResolver + (\resp -> + case resp of + Http.GoodStatus_ _ str -> + Obj.Decode.decodeString (\a -> Length.meters (a / 2)) jeepDecoder str + + _ -> + Err "Failed to load mesh" + ) + , timeout = Nothing + } + |> Task.andThen + (\fn -> + Scene3d.Material.load urls.texture + |> Task.mapError (\_ -> "Failed to load texture") + |> Task.map (\texture -> fn (Scene3d.Material.texturedMatte texture)) + ) + + +settings : Jeep -> CarSettings +settings jeep = + { downDirection = Direction3d.negativeZ + , rightDirection = Direction3d.negativeX + , forwardDirection = Direction3d.negativeY + , suspensionRestLength = Quantity.multiplyBy 0.4 jeep.wheelRadius + , minSuspensionLength = Length.meters 0 + , maxSuspensionLength = Quantity.multiplyBy 1.2 jeep.wheelRadius + , radius = jeep.wheelRadius + , suspensionStiffness = 30 + , dampingCompression = 4.4 + , dampingRelaxation = 2.3 + , frictionSlip = 5 + , rollInfluence = 0.01 + , maxSuspensionForce = Force.newtons 100000 + } + + +wheels : Jeep -> List (Wheel id) +wheels jeep = + List.map + (\axis -> + { defaultWheel + | chassisConnectionPoint = + Axis3d.originPoint axis + |> Point3d.translateIn Direction3d.z (Quantity.multiplyBy 0.2 jeep.wheelRadius) + , axis = axis + } + ) + jeep.wheelAxes + + +jeepDecoder : Decoder (Scene3d.Material.Textured BodyCoordinates -> Jeep) +jeepDecoder = + Obj.Decode.map5 + (\convexBase convexWindow chassis wheel wheelAxes -> + let + wheelBounds = + BoundingBox3d.hull Point3d.origin (TriangularMesh.vertices wheel |> Array.toList |> List.map .position) + + ( wheelWidth, wheelDiameter, _ ) = + BoundingBox3d.dimensions wheelBounds + + wheelMesh = + Scene3d.Mesh.texturedFaces wheel + + chassisMesh = + Scene3d.Mesh.texturedFaces chassis + in + \material -> + { collider = [ Shape.unsafeConvex convexBase, Shape.unsafeConvex convexWindow ] + , chassis = chassisMesh + , chassisShadow = Scene3d.Mesh.shadow chassisMesh + , wheel = wheelMesh + , wheelShadow = Scene3d.Mesh.shadow wheelMesh + , wheelAxes = wheelAxes + , wheelRadius = Quantity.half wheelDiameter + , wheelWidth = wheelWidth + , material = material + } + ) + (Obj.Decode.object "convex-base_Base" (Obj.Decode.trianglesIn Frame3d.atOrigin)) + (Obj.Decode.object "convex-window_Window" (Obj.Decode.trianglesIn Frame3d.atOrigin)) + (startsWith "chassis" (Obj.Decode.texturedFacesIn Frame3d.atOrigin)) + (Obj.Decode.object "Wheel" (Obj.Decode.texturedFacesIn Frame3d.atOrigin)) + (Obj.Decode.combine + [ Obj.Decode.object "front-left_Axis3d" axis3d + , Obj.Decode.object "front-right_Axis3d" axis3d + , Obj.Decode.object "rear-left_Axis3d" axis3d + , Obj.Decode.object "rear-right_Axis3d" axis3d + ] + ) + + +startsWith : String -> Decoder a -> Decoder a +startsWith prefix = + Obj.Decode.filter + (\properties -> + case properties.object of + Nothing -> + False + + Just object -> + String.startsWith prefix object + ) + + +axis3d : Decoder (Axis3d Meters BodyCoordinates) +axis3d = + Obj.Decode.polylinesIn Frame3d.atOrigin + |> Obj.Decode.andThen + (\lines -> + case lines of + line :: _ -> + case Polyline3d.vertices line of + p1 :: p2 :: _ -> + case Axis3d.throughPoints p1 p2 of + Just axis -> + Obj.Decode.succeed axis + + Nothing -> + Obj.Decode.fail "Failed to constuct axis" + + _ -> + Obj.Decode.fail "Expected at least two points" + + _ -> + Obj.Decode.fail "Expected at least one line" + ) diff --git a/sandbox/review/src/ReviewConfig.elm b/sandbox/review/src/ReviewConfig.elm index f49c0c4..dcb0cac 100644 --- a/sandbox/review/src/ReviewConfig.elm +++ b/sandbox/review/src/ReviewConfig.elm @@ -30,7 +30,7 @@ config = , NoUnused.CustomTypeConstructorArgs.rule , NoUnused.Dependencies.rule , NoUnused.Exports.rule - |> Review.Rule.ignoreErrorsForFiles ["src/Common/Camera.elm"] + |> Review.Rule.ignoreErrorsForFiles [ "src/Common/Camera.elm" ] , NoUnused.Modules.rule , NoUnused.Parameters.rule , NoUnused.Patterns.rule diff --git a/scripts/gh-pages.sh b/scripts/gh-pages.sh index 07ade3a..2fb50bc 100755 --- a/scripts/gh-pages.sh +++ b/scripts/gh-pages.sh @@ -32,6 +32,7 @@ for example in *.elm; do elm make $example --optimize --output ../../gh-pages$version_path/examples/$lower/index.html done cp Duckling.obj.txt Duckling.png ../../gh-pages$version_path/examples/duckling +cp Jeep.obj.txt Jeep.png ../../gh-pages$version_path/examples/raycast-car cp ../../elm-physics.gif ../../gh-pages$version_path/examples cd ../../gh-pages