1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
package my3d; import java.util.ArrayList; import my3d._math3d._transform; public class _shape3d { public static class _line { public double[] v1, v2; public _line(double[] v1, double[] v2) { this.v1 = v1; this.v2 = v2; } } public static class _plane { public double[] nor = new double[3]; public double len; private static double[] v_buf1 = new double[3], v_buf2 = new double[3]; public _plane(double[] v1, double[] v2, double[] v3) { _math3d.cross( _math3d.sub(v2, v1, v_buf1), _math3d.sub(v3, v2, v_buf2), nor); _math3d.normalize(nor, nor); len = _math3d.dot(nor, v1); } public _plane(_line line) { _math3d.cross(line.v1, line.v2, nor); } public _plane(_plane plane, double[] v1, double[] v2) { _math3d.cross( _math3d.sub(v2, v1, v_buf1), plane.nor, nor); len = _math3d.dot(nor, v1); } public double len_to(double[] v) { return _math3d.dot(nor, v) - len; } } private static final double[][] BOX_VERTICES = { {1, 1, 1}, {1, 1, 0}, {0, 1, 0}, {0, 1, 1}, {1, 0, 1}, {1, 0, 0}, {0, 0, 0}, {0, 0, 1}, }; private static final int[][] RECT_FACES = { {0, 1, 2, 3}, {3, 2, 1, 0}, }; private static final int[][] BOX_FACES = { {0, 1, 2, 3}, {7, 6, 5, 4}, {0, 4, 5, 1}, {1, 5, 6, 2}, {2, 6, 7, 3}, {3, 7, 4, 0}, }; private double[][] vertices; private int[][] lines, faces; public _shape3d(double[][] vertices, int[][] lines, int[][] faces) { this.vertices = vertices; this.lines = lines; this.faces = faces; } // 線群作成 public static _shape3d create_lines(ArrayList<double[]> v_list) { int n = v_list.size(); double[][] va = new double[n][]; int[][] lines = new int[n / 2][2]; for (int i = 0; i < n; i++) { va[i] = v_list.get(i); lines[i / 2][i % 2] = i; } return new _shape3d(va, lines, null); } // 面作成 public static _shape3d create_rect( double x, double z, _transform tf ) { double[][] va = new double[4][3]; double[] v; for (int i = 0; i < 4; i++) { v = va[i]; _math3d.copy_vector(BOX_VERTICES[i % 4 + 4], v); v[0] = (v[0] - 0.5) * x; v[2] = (v[2] - 0.5) * z; _math3d.mul(tf, v, v); } return new _shape3d(va, null, RECT_FACES); } // 箱作成 public static _shape3d create_box( double x, double y, double z, _transform tf ) { double[][] va = new double[8][3]; double[] v; for (int i = 0; i < 8; i++) { v = va[i]; _math3d.copy_vector(BOX_VERTICES[i], v); v[0] = (v[0] - 0.5) * x; v[1] = (v[1] - 0.5) * y; v[2] = (v[2] - 0.5) * z; _math3d.mul(tf, v, v); } return new _shape3d(va, null, BOX_FACES); } public double[][] get_vertices() { return vertices; } public int[][] get_lines() { return lines; } public int[][] get_faces() { return faces; } private static double[] v_out1 = new double[3], v_out2 = new double[3]; // 境界線取得 private static double[][] va_buf = new double[2][]; public static _shape3d border(_shape3d s1, _shape3d s2) { int[][] faces1, faces2; double[][] vertices1, vertices2; vertices1 = s1.get_vertices(); faces1 = s1.get_faces(); vertices2 = s2.get_vertices(); faces2 = s2.get_faces(); if (faces1 == null || faces2 == null) return null; ArrayList<double[][]> s1_vertices_list = new ArrayList<>(); ArrayList<ArrayList<_plane>> s2_planes_list = new ArrayList<>(); double [][] va; for (int[] face : faces1) { va = new double[face.length][]; for (int i = 0; i < face.length; i++) va[i] = vertices1[face[i]]; s1_vertices_list.add(va); } va = vertices2; ArrayList<_plane> pa; _plane plane; int j; for (int[] face : faces2) { pa = new ArrayList<>(); plane = new _plane(va[face[0]], va[face[1]], va[face[2]]); for (int i = 0; i < face.length; i++) { j = (i + 1) % face.length; pa.add(new _plane(plane, va[face[i]], va[face[j]])); } pa.add(plane); s2_planes_list.add(pa); } ArrayList<double[]> v_list = new ArrayList<>(); double[] v1, v2; int result; for (ArrayList<_plane> planes : s2_planes_list) { plane = planes.remove(planes.size() - 1); for (double[][] vertices : s1_vertices_list) { if (!hit(vertices, plane, va_buf)) continue; v1 = va_buf[0]; v2 = va_buf[1]; result = clip(v1, v2, planes, v_out1, v_out2); if (result == -1) continue; if (result == 1) { v1 = v_out1; v_out1 = new double[3]; } else if (result == 2) { v2 = v_out2; v_out2 = new double[3]; } else if (result == 3) { v1 = v_out1; v_out1 = new double[3]; v2 = v_out2; v_out2 = new double[3]; } v_list.add(v1); v_list.add(v2); } } return create_lines(v_list); } public static boolean hit( double[][] vertices, _plane plane, double[][] vao ) { double[] v1, v2; double t, l1, l2; int count = 0, j; for (int i = 0; i < vertices.length; i++) { j = (i + 1) % vertices.length; v1 = vertices[i]; v2 = vertices[j]; l1 = plane.len_to(v1); l2 = plane.len_to(v2); if ((l1 < 0) == (l2 < 0)) continue; t = l2 / (l2 - l1); vao[count++] = _math3d.lerp(v1, v2, t, new double[3]); if (count == 2) return true; } return false; } public static int clip( double[] v1, double[] v2, ArrayList<_plane> clip_plane_list, double[] vo1, double[] vo2 ) { boolean b_out1 = false, b_out2 = false; double l1, l2, t; _math3d.copy_vector(v1, vo1); v1 = vo1; _math3d.copy_vector(v2, vo2); v2 = vo2; for (_plane plane : clip_plane_list) { l1 = plane.len_to(v1); l2 = plane.len_to(v2); if ((l1 >= 0) == (l2 >= 0)) { if (l1 >= 0) return -1; // v1、v2ともに外 continue; } t = l2 / (l2 - l1); if (l1 >= 0) { b_out1 = true; _math3d.lerp(v1, v2, t, v1); } else { b_out2 = true; _math3d.lerp(v1, v2, t, v2); } } if (b_out1 && b_out2) return 3; // 貫通 else if (b_out2) return 2; // v1が内、v2が外 else if (b_out1) return 1; // v1が外、v2が内 return 0; // v1、v2ともに内 } }