1 /* Supporting different types and containers. 2 * Copyright (C) 2017 Marko Semet 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 */ 17 module structuresd.dimension; 18 19 private 20 { 21 import std.meta; 22 import std.traits; 23 import structuresd.utils; 24 } 25 26 public final struct Point(uint DIMS, TYPE = double) 27 { 28 private static pure 29 { 30 enum bool goodSingualType(T) = __traits(compiles, {T a; TYPE b = a;}); 31 bool suiableTypes(T...)() 32 { 33 bool result = true; 34 static foreach(I; T) 35 { 36 static if(!goodSingualType!I && !(__traits(isSame, TemplateOf!I, Point) && goodSingualType!(TemplateArgsOf!I[1]))) 37 { 38 result = false; 39 } 40 } 41 return result; 42 } 43 ulong countDims(T...)() 44 { 45 ulong result = 0; 46 static foreach(I; T) 47 { 48 static if(goodSingualType!I) 49 { 50 result++; 51 } 52 else static if(__traits(isSame, TemplateOf!I, Point) && goodSingualType!(TemplateArgsOf!I[1])) 53 { 54 result += TemplateArgsOf!I[0]; 55 } 56 else 57 { 58 static assert(false); 59 } 60 } 61 return result; 62 } 63 } 64 65 public TYPE[DIMS] dims; 66 67 public this(T...)(T data) if(suiableTypes!T && countDims!T == DIMS) 68 { 69 ulong position = 0; 70 static foreach(i; data) 71 { 72 static if(goodSingualType!(typeof(i))) 73 { 74 this.dims[position] = i; 75 position++; 76 } 77 else static if(__traits(isSame, TemplateOf!(typeof(i)), Point) && goodSingualType!(TemplateArgsOf!(typeof(i))[1])) 78 { 79 static foreach(j; i.dims) 80 { 81 this.dims[position] = j; 82 position++; 83 } 84 } 85 else 86 { 87 static assert(false); 88 } 89 } 90 } 91 public this(TYPE[DIMS] dims) 92 { 93 this.dims = dims; 94 } 95 96 public Point!(DIMS, TYPE) opBinary(string OP)(TYPE scalar) if(OP == "*" || OP == "/") 97 { 98 Point!(DIMS, TYPE) result; 99 static foreach(uint i; 0..DIMS) 100 { 101 mixin("result.dims[i] = this.dims[i] " ~ OP ~ " scalar;"); 102 } 103 return result; 104 } 105 106 public Point!(DIMS, TYPE) opBinary(string OP)(Point p) if(OP == "+" || OP == "-") 107 { 108 Point!(DIMS, TYPE) result; 109 static foreach(uint i; 0..DIMS) 110 { 111 mixin("result.dims[i] = this.dims[i] " ~ OP ~ " p.dims[i];"); 112 } 113 return result; 114 } 115 116 public ref Point!(DIMS, TYPE) opOpAssign(string OP)(Point!(DIMS, TYPE) p) if(OP == "+" || OP == "-") 117 { 118 static foreach(uint i; 0..DIMS) 119 { 120 mixin("this.dims[i] " ~ OP ~ "= p.dims[i];"); 121 } 122 return this; 123 } 124 } 125 126 private struct _GeometryFuns(T1, T2) 127 { 128 public nothrow pure T1 maxGeometry(T1) { T1 res; return res; } 129 public nothrow pure T2 volume() { T2 res; return res; }; 130 public nothrow pure bool contains(T1) { return false; }; 131 } 132 133 public final struct Sphere(uint DIMS, TYPE = double) 134 { 135 static assert(DIMS > 0); 136 137 public Point!(DIMS, TYPE) center; 138 public TYPE radius; 139 } 140 141 public final struct Cuboid(uint DIMS, TYPE = double) 142 { 143 public alias BASE_TYPE = TYPE; 144 145 public Point!(DIMS, TYPE) a; 146 public Point!(DIMS, TYPE) b; 147 148 public this(Point!(DIMS, TYPE) a, Point!(DIMS, TYPE) b) 149 { 150 static foreach(ulong i; 0..DIMS) 151 { 152 this.a.dims[i] = min(a.dims[i], b.dims[i]); 153 this.b.dims[i] = max(a.dims[i], b.dims[i]); 154 } 155 } 156 157 public nothrow pure Cuboid maxGeometry(Cuboid c) 158 { 159 Cuboid res; 160 static foreach(uint i; 0..DIMS) 161 { 162 res.a.dims[i] = min(this.a.dims[i], this.b.dims[i], c.a.dims[i], c.b.dims[i]); 163 res.b.dims[i] = max(this.a.dims[i], this.b.dims[i], c.a.dims[i], c.b.dims[i]); 164 } 165 return res; 166 } 167 public nothrow pure TYPE volume() 168 { 169 TYPE res; 170 for(uint i = 0; i < DIMS; i++) 171 { 172 res *= this.b.dims[i] - this.b.dims[i]; 173 } 174 return res < 0 ? -res : res; 175 } 176 public nothrow pure bool containsPoint(Point!(DIMS, TYPE) p) 177 { 178 static foreach(ulong i; 0..DIMS) 179 { 180 if((min(this.a.dims[i], this.b.dims[i]) > p.dims[i]) | (p.dims[i] > max(this.a.dims[i], this.b.dims[i]))) 181 { 182 return false; 183 } 184 } 185 return true; 186 } 187 public nothrow pure bool contains(Cuboid c) 188 { 189 return this.allDotsCheck(c) && c.allDotsCheck(this); 190 } 191 192 private pure nothrow bool allDotsCheck(Cuboid c) 193 { 194 foreach(ulong i; 0..(1 << DIMS)) 195 { 196 TYPE[DIMS] tmp; 197 static foreach(ulong j; 0..DIMS) 198 { 199 tmp[j] = ((1 << j) & i) == 0 ? this.a.dims[j] : this.b.dims[j]; 200 } 201 if(this.containsPoint(Point!(DIMS, TYPE)(tmp))) 202 { 203 return true; 204 } 205 } 206 return false; 207 } 208 } 209 210 public enum bool isGeometry(T) = __traits(hasMember, T, "BASE_TYPE") && 211 isSameContainerFunction!(_GeometryFuns!(T, T.BASE_TYPE), T, "maxGeometry") && 212 isSameContainerFunction!(_GeometryFuns!(T, T.BASE_TYPE), T, "volume") && 213 isSameContainerFunction!(_GeometryFuns!(T, T.BASE_TYPE), T, "contains"); 214 215 216 public TYPE.BASE_TYPE getInseredVolume(TYPE)(TYPE old, TYPE insert) if(isGeometry!(TYPE)) 217 { 218 return old.maxGeometry(insert).volume() - old.volume(); 219 } 220 221 private unittest 222 { 223 static assert(isSameContainerFunction!(_GeometryFuns!(Cuboid!2, Cuboid!(2).BASE_TYPE), Cuboid!2, "maxGeometry")); 224 static assert(isSameContainerFunction!(_GeometryFuns!(Cuboid!2, Cuboid!(2).BASE_TYPE), Cuboid!2, "volume")); 225 static assert(isSameContainerFunction!(_GeometryFuns!(Cuboid!2, Cuboid!(2).BASE_TYPE), Cuboid!2, "contains")); 226 static assert(isGeometry!(Cuboid!2)); 227 }