├── .gitignore ├── Makefile ├── README.md ├── examples ├── house_south ├── house_south.mtl ├── house_south.obj ├── maisel ├── maisel.mtl ├── maisel.obj ├── paper_example ├── paper_example.off ├── town ├── town.mtl ├── town.obj └── town_without_roof ├── mview ├── plane.off ├── report.pdf ├── res ├── house_south.png ├── maisel.png ├── roof_south.jpg └── town_custom_roof.png └── src ├── actions ├── actions.l ├── actions.y ├── actions_scanner.h └── actions_scanner_internal.h ├── cgacode ├── cgacode.l ├── cgacode.y ├── cgacode_driver.cpp ├── cgacode_driver.h ├── cgacode_scanner.h └── cgacode_scanner_internal.h ├── custom_join.cpp ├── custom_join.h ├── main.cpp ├── node.cpp ├── node.h ├── rule.cpp ├── rule.h ├── shape_tree.cpp ├── shape_tree.h ├── split_pattern ├── split_pattern.l ├── split_pattern.y ├── split_pattern_driver.cpp ├── split_pattern_driver.h ├── split_pattern_scanner.h └── split_pattern_scanner_internal.h ├── utils.cpp └── utils.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Precompiled Headers 7 | *.gch 8 | *.pch 9 | 10 | # Compiled Dynamic libraries 11 | *.so 12 | *.dylib 13 | *.dll 14 | 15 | # Fortran module files 16 | *.mod 17 | 18 | # Compiled Static libraries 19 | *.lai 20 | *.la 21 | *.a 22 | *.lib 23 | 24 | # Executables 25 | *.exe 26 | *.out 27 | *.app 28 | 29 | *.layout 30 | 31 | *.pdf 32 | 33 | out 34 | core 35 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | EXE = out 2 | DIRS = actions split_pattern cgacode 3 | SRCS = $(wildcard src/*.cpp) 4 | SRCS2 = $(wildcard src/actions/*.cpp) 5 | SRCS3 = $(wildcard src/split_pattern/*.cpp) 6 | SRCS4 = $(wildcard src/cgacode/*.cpp) 7 | 8 | LIBS = -lCGAL -lCGAL_Core -lmpfr -lgmp -lboost_thread -lboost_system 9 | CFLAGS = -Wall -std=c++11 -O3 -frounding-math 10 | 11 | OBJS = $(addprefix obj/,$(notdir $(SRCS:.cpp=.o))) 12 | OBJS2 = $(addprefix obj/actions/,$(notdir $(SRCS2:.cpp=.o))) 13 | OBJS3 = $(addprefix obj/split_pattern/,$(notdir $(SRCS3:.cpp=.o))) 14 | OBJS4 = $(addprefix obj/cgacode/,$(notdir $(SRCS4:.cpp=.o))) 15 | 16 | $(EXE): $(OBJS) $(OBJS2) $(OBJS3) $(OBJS4) 17 | g++ $(OBJS) $(OBJS2) $(OBJS3) $(OBJS4) -o $(EXE) $(LIBS) 18 | 19 | clean: 20 | rm -f *~ $(EXE) $(OBJS) $(OBJS2) $(OBJS3) $(OBJS4) 21 | 22 | rm_parsers: 23 | cd src/ ; for d in $(DIRS); do (cd $$d ; rm -f *_parser* *_scanner.cpp stack.hh) done 24 | 25 | gen_parsers: 26 | cd src/ ; for d in $(DIRS); do (cd $$d ; flex -d *.l ; bison *.y) done 27 | 28 | obj: 29 | mkdir obj; cd obj; for d in $(DIRS); do (mkdir $$d) done 30 | 31 | obj/main.o: src/main.cpp 32 | g++ -c $< -o $@ $(CFLAGS) 33 | obj/%.o: src/%.cpp src/%.h 34 | g++ -c $< -o $@ $(CFLAGS) 35 | obj/actions/%.o: src/actions/%.cpp 36 | g++ -c $< -o $@ $(CFLAGS) 37 | obj/split_pattern/%.o: src/split_pattern/%.cpp 38 | g++ -c $< -o $@ $(CFLAGS) 39 | obj/cgacode/%.o: src/cgacode/%.cpp 40 | g++ -c $< -o $@ $(CFLAGS) 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CGA_interpreter 2 | 3 | This program is a procedural architecture generator inspired by CGA and CGA++ grammars 4 | https://www.cs.purdue.edu/homes/aliaga/cs535-12/lectures/grammars/proc-mod-bldgs.pdf 5 | http://research.michael-schwarz.com/publ/2015/cgapp/ 6 | 7 | **For more details read report.pdf** 8 | 9 | The current project is built only for GNU/Linux. It requires: 10 | ``` 11 | flex 12 | bison 13 | libcgal-dev 14 | ``` 15 | 16 | You can also use `meshlab` to visualize the `.obj` generated files. You'll need version 1.3.3 or higher as in 1.3.2, the import of OBJs is broken. 17 | 18 | To build, create the necessary object folders for the first time 19 | ``` 20 | make obj 21 | ``` 22 | 23 | Then run 24 | ``` 25 | make gen_parsers 26 | make 27 | ``` 28 | -------------------------------------------------------------------------------- /examples/house_south: -------------------------------------------------------------------------------- 1 | initFromRect 10 10 2 | setOutputFilename "examples/house_south.obj" 3 | setRoofZoom 2 4 | setRoofTexture "../res/roof_south.jpg" 5 | setTextureFile "../res/house_south.png" 6 | addTextureRect "garage" 0. 0. 0.5 0.45 7 | addTextureRect "wall" 0.5 0. 1. 0.5 8 | addTextureRect "window" 0. 0.5 0.5 1. 9 | addTextureRect "door" 0.5 0.5. 1. 1. 10 | 11 | %% 12 | 13 | Foundations --> createRoof(20,0.3) split("x") {~1: Garage | ~2: Center1 | ~1: EdgeZ } ;; 14 | 15 | Garage --> split("z") {2.5: GrowLevel roof() TextureGarage | ~1: EdgeZ} ;; 16 | 17 | Center1 --> split("z") {~1:Front | ~2: GrowLevel Center | ~1: EdgeX} ;; 18 | 19 | Front --> split("x") {~1: GrowLevel roof() TextureEntrance Room | ~1: Edge} ;; 20 | 21 | EdgeX --> split("x") {~2.5: Edge}* ;; 22 | EdgeZ --> split("z") {~2.5: Edge}* ;; 23 | RoomX --> split("x") {~2.5: Room}* ;; 24 | 25 | Edge --> Nothing ;; 26 | Edge --> Room ;; 27 | 28 | Room --> GrowLevel roof() TextureWall ;; 29 | Room --> GrowLevel TextureWall Room ;; 30 | 31 | Center --> split("z") {~2.5:RoomX}* ;; 32 | 33 | TextureGarage --> selectFaces("zneg") setTexture("garage") 34 | selectFaces("") selectFaces("zpos") selectFaces("x") setTexture("wall") ;; 35 | 36 | TextureEntrance --> TextureWall selectFaces("") selectFaces("zneg") setTexture("door") ;; 37 | 38 | TextureWall --> selectFaces("all") setTexture("wall") PaintWindow ;; 39 | PaintWindow --> selectFaces("z") setTexture("window") ;; 40 | PaintWindow --> selectFaces("x") setTexture("window") ;; 41 | PaintWindow 2 --> selectFaces("all") setTexture("window") ;; 42 | 43 | GrowLevel --> selectFaces("") selectFaces("ypos") extrude(2.5) ;; 44 | 45 | setRecDepth GrowLevel 7 46 | fallback GrowLevel --> roof() ;; 47 | -------------------------------------------------------------------------------- /examples/house_south.mtl: -------------------------------------------------------------------------------- 1 | newmtl Texture 2 | map_Kd ../res/house_south.png 3 | newmtl RoofTexture 4 | map_Kd ../res/roof_south.jpg 5 | -------------------------------------------------------------------------------- /examples/house_south.obj: -------------------------------------------------------------------------------- 1 | # CGA-_interpreter generated building 2 | mtllib house_south.mtl 3 | o Building 4 | v -5 0 -5 5 | v -5 0 -2.5 6 | v -2.5 0 -5 7 | v -2.5 0 -2.5 8 | v -5 0 -5 9 | v -5 2.5 -5 10 | v -5 0 -2.5 11 | v -5 2.5 -2.5 12 | v -2.5 0 -2.5 13 | v -2.5 2.5 -2.5 14 | v -2.5 0 -5 15 | v -2.5 2.5 -5 16 | v -5 0 -2.5 17 | v -5 0 0 18 | v -2.5 0 -2.5 19 | v -2.5 0 0 20 | v -5 0 0 21 | v -5 0 2.5 22 | v -2.5 0 0 23 | v -2.5 0 2.5 24 | v -5 0 0 25 | v -5 2.5 0 26 | v -5 0 2.5 27 | v -5 2.5 2.5 28 | v -2.5 0 2.5 29 | v -2.5 2.5 2.5 30 | v -2.5 0 0 31 | v -2.5 2.5 0 32 | v -5 2.5 0 33 | v -5 5 0 34 | v -5 2.5 2.5 35 | v -5 5 2.5 36 | v -2.5 2.5 2.5 37 | v -2.5 5 2.5 38 | v -2.5 2.5 0 39 | v -2.5 5 0 40 | v -5 5 0 41 | v -5 7.5 0 42 | v -5 5 2.5 43 | v -5 7.5 2.5 44 | v -2.5 5 2.5 45 | v -2.5 7.5 2.5 46 | v -2.5 5 0 47 | v -2.5 7.5 0 48 | v -5 7.5 0 49 | v -5 10 0 50 | v -5 7.5 2.5 51 | v -5 10 2.5 52 | v -2.5 7.5 2.5 53 | v -2.5 10 2.5 54 | v -2.5 7.5 0 55 | v -2.5 10 0 56 | v -5 0 2.5 57 | v -5 0 5 58 | v -2.5 0 2.5 59 | v -2.5 0 5 60 | v -2.5 0 -5 61 | v 0 0 -5 62 | v -2.5 0 -2.5 63 | v 0 0 -2.5 64 | v -2.5 0 -5 65 | v -2.5 2.5 -5 66 | v -2.5 0 -2.5 67 | v -2.5 2.5 -2.5 68 | v 0 0 -2.5 69 | v 0 2.5 -2.5 70 | v 0 0 -5 71 | v 0 2.5 -5 72 | v -2.5 2.5 -5 73 | v -2.5 5 -5 74 | v -2.5 2.5 -2.5 75 | v -2.5 5 -2.5 76 | v 0 2.5 -2.5 77 | v 0 5 -2.5 78 | v 0 2.5 -5 79 | v 0 5 -5 80 | v 0 0 -5 81 | v 2.5 0 -5 82 | v 0 0 -2.5 83 | v 2.5 0 -2.5 84 | v -2.5 0 -2.5 85 | v -2.5 0 2.5 86 | v 2.5 0 -2.5 87 | v 2.5 0 2.5 88 | v -2.5 0 -2.5 89 | v 0 0 -2.5 90 | v -2.5 0 0 91 | v 0 0 0 92 | v -2.5 2.5 -2.5 93 | v 0 2.5 -2.5 94 | v -2.5 2.5 0 95 | v 0 2.5 0 96 | v -2.5 2.5 -2.5 97 | v -2.5 5 -2.5 98 | v -2.5 2.5 0 99 | v -2.5 5 0 100 | v 0 2.5 0 101 | v 0 5 0 102 | v 0 2.5 -2.5 103 | v 0 5 -2.5 104 | v 0 0 -2.5 105 | v 2.5 0 -2.5 106 | v 0 0 0 107 | v 2.5 0 0 108 | v 0 2.5 -2.5 109 | v 2.5 2.5 -2.5 110 | v 0 2.5 0 111 | v 2.5 2.5 0 112 | v 0 2.5 -2.5 113 | v 0 5 -2.5 114 | v 0 2.5 0 115 | v 0 5 0 116 | v 2.5 2.5 0 117 | v 2.5 5 0 118 | v 2.5 2.5 -2.5 119 | v 2.5 5 -2.5 120 | v -2.5 0 0 121 | v 0 0 0 122 | v -2.5 0 2.5 123 | v 0 0 2.5 124 | v -2.5 2.5 0 125 | v 0 2.5 0 126 | v -2.5 2.5 2.5 127 | v 0 2.5 2.5 128 | v -2.5 2.5 0 129 | v -2.5 5 0 130 | v -2.5 2.5 2.5 131 | v -2.5 5 2.5 132 | v 0 2.5 2.5 133 | v 0 5 2.5 134 | v 0 2.5 0 135 | v 0 5 0 136 | v 0 0 0 137 | v 2.5 0 0 138 | v 0 0 2.5 139 | v 2.5 0 2.5 140 | v 0 2.5 0 141 | v 2.5 2.5 0 142 | v 0 2.5 2.5 143 | v 2.5 2.5 2.5 144 | v 0 2.5 0 145 | v 0 5 0 146 | v 0 2.5 2.5 147 | v 0 5 2.5 148 | v 2.5 2.5 2.5 149 | v 2.5 5 2.5 150 | v 2.5 2.5 0 151 | v 2.5 5 0 152 | v -2.5 0 2.5 153 | v 0 0 2.5 154 | v -2.5 0 5 155 | v 0 0 5 156 | v 0 0 2.5 157 | v 2.5 0 2.5 158 | v 0 0 5 159 | v 2.5 0 5 160 | v 2.5 0 -5 161 | v 2.5 0 -2.5 162 | v 5 0 -5 163 | v 5 0 -2.5 164 | v 2.5 0 -5 165 | v 2.5 2.5 -5 166 | v 2.5 0 -2.5 167 | v 2.5 2.5 -2.5 168 | v 5 0 -2.5 169 | v 5 2.5 -2.5 170 | v 5 0 -5 171 | v 5 2.5 -5 172 | v 2.5 2.5 -5 173 | v 2.5 5 -5 174 | v 2.5 2.5 -2.5 175 | v 2.5 5 -2.5 176 | v 5 2.5 -2.5 177 | v 5 5 -2.5 178 | v 5 2.5 -5 179 | v 5 5 -5 180 | v 2.5 5 -5 181 | v 2.5 7.5 -5 182 | v 2.5 5 -2.5 183 | v 2.5 7.5 -2.5 184 | v 5 5 -2.5 185 | v 5 7.5 -2.5 186 | v 5 5 -5 187 | v 5 7.5 -5 188 | v 2.5 0 -2.5 189 | v 2.5 0 0 190 | v 5 0 -2.5 191 | v 5 0 0 192 | v 2.5 0 -2.5 193 | v 2.5 2.5 -2.5 194 | v 2.5 0 0 195 | v 2.5 2.5 0 196 | v 5 0 0 197 | v 5 2.5 0 198 | v 5 0 -2.5 199 | v 5 2.5 -2.5 200 | v 2.5 0 0 201 | v 2.5 0 2.5 202 | v 5 0 0 203 | v 5 0 2.5 204 | v 2.5 0 2.5 205 | v 2.5 0 5 206 | v 5 0 2.5 207 | v 5 0 5 208 | v -5 9.89081 0 209 | v -2.5 9.89081 0 210 | v -2.5 9.89081 2.5 211 | v -5 9.89081 2.5 212 | v -3.75 10.3458 1.25 213 | v -5 7.39081 0 214 | v -2.5 7.39081 0 215 | v -2.5 7.39081 2.5 216 | v -5 7.39081 2.5 217 | v -3.75 7.84577 1.25 218 | v 2.5 7.39081 -5 219 | v 5 7.39081 -5 220 | v 5 7.39081 -2.5 221 | v 2.5 7.39081 -2.5 222 | v 3.75 7.84577 -3.75 223 | v 2.5 4.89081 -5 224 | v 5 4.89081 -5 225 | v 5 4.89081 -2.5 226 | v 2.5 4.89081 -2.5 227 | v 2.5 4.89081 0 228 | v 2.5 4.89081 2.5 229 | v 0 4.89081 2.5 230 | v -2.5 4.89081 2.5 231 | v -5 4.89081 2.5 232 | v -5 4.89081 0 233 | v -2.5 4.89081 0 234 | v -2.5 4.89081 -2.5 235 | v -2.5 4.89081 -5 236 | v 0 4.89081 -5 237 | v 0 4.89081 -2.5 238 | v 2.5 4.89081 -2.5 239 | v 0 6.54307e+307 0 240 | v 0 6.54307e+307 0 241 | v 0 6.54307e+307 0 242 | v 0 6.54307e+307 0 243 | v -1.25 5.34577 -3.75 244 | v -3.75 5.34577 1.25 245 | v 3.75 5.34577 -3.75 246 | v -2.5 5.34577 1.25 247 | v -1.25 5.34577 -2.5 248 | v -1.25 5.34577 1.25 249 | v -1.25 5.34577 -1.25 250 | v 0 5.80073 0 251 | v 2.5 2.39081 -5 252 | v 5 2.39081 -5 253 | v 5 2.39081 -2.5 254 | v 5 2.39081 0 255 | v 2.5 2.39081 0 256 | v 2.5 2.39081 2.5 257 | v 0 2.39081 2.5 258 | v -2.5 2.39081 2.5 259 | v -5 2.39081 2.5 260 | v -5 2.39081 0 261 | v -2.5 2.39081 0 262 | v -2.5 2.39081 -2.5 263 | v -5 2.39081 -2.5 264 | v -5 2.39081 -5 265 | v -2.5 2.39081 -5 266 | v 0 2.39081 -5 267 | v 0 2.39081 -2.5 268 | v 2.5 2.39081 -2.5 269 | v 3.75 2.84577 -3.75 270 | v -3.75 2.84577 1.25 271 | v -3.75 2.84577 -3.75 272 | v 3.75 2.84577 -2.5 273 | v -2.5 2.84577 -3.75 274 | v 3.75 2.84577 -1.25 275 | v -2.5 2.84577 1.25 276 | v 1.25 2.84577 -1.25 277 | v -1.25 2.84577 1.25 278 | v -1.25 2.84577 -3.75 279 | v -1.25 2.84577 -1.25 280 | v -0 3.30073 0 281 | vt 0 0 282 | vt 0 0 283 | vt 0 0 284 | vt 0 0 285 | vt 0 0 286 | vt 0.5 0 287 | vt 0.5 0.45 288 | vt 0 0.45 289 | vt 0.5 0 290 | vt 1 0 291 | vt 1 0.5 292 | vt 0.5 0.5 293 | vt 0 0.5 294 | vt 0.5 0.5 295 | vt 0.5 1 296 | vt 0 1 297 | vt 0.5 0.5 298 | vt 1 0.5 299 | vt 1 1 300 | vt 0.5 1 301 | vt 0 0 302 | vt 1.25 0 303 | vt 0.625 0.665111 304 | vt -1.25 inf 305 | vt 2.5 inf 306 | vt 1.25 inf 307 | vt 1.25 1.33022 308 | vt 0 1.33022 309 | vt 1.25 0.665111 310 | vt -0 0.665111 311 | vt 1.875 0.665111 312 | vt -0.625 0.665111 313 | vt 0 inf 314 | usemtl Texture 315 | s off 316 | f 1/1 2/2 4/3 3/4 317 | f 5/9 7/10 8/11 6/12 318 | f 7/9 9/10 10/11 8/12 319 | f 9/9 11/10 12/11 10/12 320 | f 11/5 5/6 6/7 12/8 321 | f 6/1 8/2 10/3 12/4 322 | f 13/1 14/2 16/3 15/4 323 | f 17/1 18/2 20/3 19/4 324 | f 21/13 23/14 24/15 22/16 325 | f 23/13 25/14 26/15 24/16 326 | f 25/13 27/14 28/15 26/16 327 | f 27/13 21/14 22/15 28/16 328 | f 22/13 24/14 26/15 28/16 329 | f 29/13 31/14 32/15 30/16 330 | f 31/13 33/14 34/15 32/16 331 | f 33/13 35/14 36/15 34/16 332 | f 35/13 29/14 30/15 36/16 333 | f 30/13 32/14 34/15 36/16 334 | f 37/13 39/14 40/15 38/16 335 | f 39/13 41/14 42/15 40/16 336 | f 41/13 43/14 44/15 42/16 337 | f 43/13 37/14 38/15 44/16 338 | f 38/13 40/14 42/15 44/16 339 | f 45/13 47/14 48/15 46/16 340 | f 47/13 49/14 50/15 48/16 341 | f 49/13 51/14 52/15 50/16 342 | f 51/13 45/14 46/15 52/16 343 | f 46/13 48/14 50/15 52/16 344 | f 53/1 54/2 56/3 55/4 345 | f 57/1 59/2 60/3 58/4 346 | f 61/13 63/14 64/15 62/16 347 | f 63/13 65/14 66/15 64/16 348 | f 65/13 67/14 68/15 66/16 349 | f 67/17 61/18 62/19 68/20 350 | f 62/13 64/14 66/15 68/16 351 | f 69/13 71/14 72/15 70/16 352 | f 71/13 73/14 74/15 72/16 353 | f 73/13 75/14 76/15 74/16 354 | f 75/13 69/14 70/15 76/16 355 | f 70/13 72/14 74/15 76/16 356 | f 77/1 79/2 80/3 78/4 357 | f 81/1 82/2 84/3 83/4 358 | f 85/1 87/2 91/3 89/4 359 | f 87/1 88/2 92/3 91/4 360 | f 88/1 86/2 90/3 92/4 361 | f 86/1 85/2 89/3 90/4 362 | f 89/1 91/2 92/3 90/4 363 | f 93/13 95/14 96/15 94/16 364 | f 95/13 97/14 98/15 96/16 365 | f 97/13 99/14 100/15 98/16 366 | f 99/13 93/14 94/15 100/16 367 | f 94/13 96/14 98/15 100/16 368 | f 101/1 103/2 107/3 105/4 369 | f 103/1 104/2 108/3 107/4 370 | f 104/1 102/2 106/3 108/4 371 | f 102/1 101/2 105/3 106/4 372 | f 105/1 107/2 108/3 106/4 373 | f 109/13 111/14 112/15 110/16 374 | f 111/13 113/14 114/15 112/16 375 | f 113/13 115/14 116/15 114/16 376 | f 115/13 109/14 110/15 116/16 377 | f 110/13 112/14 114/15 116/16 378 | f 117/1 119/2 123/3 121/4 379 | f 119/1 120/2 124/3 123/4 380 | f 120/1 118/2 122/3 124/4 381 | f 118/1 117/2 121/3 122/4 382 | f 121/1 123/2 124/3 122/4 383 | f 125/13 127/14 128/15 126/16 384 | f 127/13 129/14 130/15 128/16 385 | f 129/13 131/14 132/15 130/16 386 | f 131/13 125/14 126/15 132/16 387 | f 126/13 128/14 130/15 132/16 388 | f 133/1 135/2 139/3 137/4 389 | f 135/1 136/2 140/3 139/4 390 | f 136/1 134/2 138/3 140/4 391 | f 134/1 133/2 137/3 138/4 392 | f 137/1 139/2 140/3 138/4 393 | f 141/13 143/14 144/15 142/16 394 | f 143/13 145/14 146/15 144/16 395 | f 145/13 147/14 148/15 146/16 396 | f 147/13 141/14 142/15 148/16 397 | f 142/13 144/14 146/15 148/16 398 | f 149/1 151/2 152/3 150/4 399 | f 153/1 155/2 156/3 154/4 400 | f 157/1 158/2 160/3 159/4 401 | f 161/13 163/14 164/15 162/16 402 | f 163/13 165/14 166/15 164/16 403 | f 165/13 167/14 168/15 166/16 404 | f 167/13 161/14 162/15 168/16 405 | f 162/13 164/14 166/15 168/16 406 | f 169/13 171/14 172/15 170/16 407 | f 171/13 173/14 174/15 172/16 408 | f 173/13 175/14 176/15 174/16 409 | f 175/13 169/14 170/15 176/16 410 | f 170/13 172/14 174/15 176/16 411 | f 177/13 179/14 180/15 178/16 412 | f 179/13 181/14 182/15 180/16 413 | f 181/13 183/14 184/15 182/16 414 | f 183/13 177/14 178/15 184/16 415 | f 178/13 180/14 182/15 184/16 416 | f 185/1 186/2 188/3 187/4 417 | f 189/13 191/14 192/15 190/16 418 | f 191/13 193/14 194/15 192/16 419 | f 193/13 195/14 196/15 194/16 420 | f 195/13 189/14 190/15 196/16 421 | f 190/13 192/14 194/15 196/16 422 | f 197/1 198/2 200/3 199/4 423 | f 201/1 202/2 204/3 203/4 424 | usemtl RoofTexture 425 | s off 426 | f 205/22 208/21 209/23 427 | f 206/22 205/21 209/23 428 | f 207/22 206/21 209/23 429 | f 208/22 207/21 209/23 430 | f 210/22 213/21 214/23 431 | f 211/22 210/21 214/23 432 | f 212/22 211/21 214/23 433 | f 213/22 212/21 214/23 434 | f 215/22 218/21 219/23 435 | f 216/22 215/21 219/23 436 | f 217/22 216/21 219/23 437 | f 218/22 217/21 219/23 438 | f 220/22 235/21 236/24 242/23 439 | f 221/22 220/21 242/23 440 | f 222/22 221/21 242/23 441 | f 223/22 222/21 242/23 237/25 442 | f 224/22 223/21 238/26 247/27 443 | f 225/22 224/21 247/28 444 | f 226/22 225/21 247/27 445 | f 227/22 226/21 247/28 245/23 243/29 446 | f 228/22 227/21 243/30 241/23 447 | f 229/22 228/21 241/23 448 | f 230/22 229/21 241/23 243/29 245/31 449 | f 231/22 230/21 245/32 247/28 246/23 244/29 450 | f 232/22 231/21 244/30 240/23 451 | f 233/22 232/21 240/23 452 | f 234/22 233/21 240/23 244/29 246/31 453 | f 235/22 234/21 246/32 247/28 239/33 454 | f 248/22 265/21 271/32 269/30 266/23 455 | f 249/22 248/21 266/23 456 | f 250/22 249/21 266/23 269/29 457 | f 251/22 250/21 269/30 271/23 458 | f 252/22 251/21 271/23 273/31 459 | f 253/22 252/21 273/32 277/28 460 | f 254/22 253/21 277/27 461 | f 255/22 254/21 277/28 274/23 272/29 462 | f 256/22 255/21 272/30 267/23 463 | f 257/22 256/21 267/23 464 | f 258/22 257/21 267/23 272/29 274/31 465 | f 259/22 258/21 274/32 277/28 276/23 275/31 466 | f 260/22 259/21 275/32 270/30 268/23 467 | f 261/22 260/21 268/23 468 | f 262/22 261/21 268/23 270/29 469 | f 263/22 262/21 270/30 275/23 470 | f 264/22 263/21 275/23 276/31 471 | f 265/22 264/21 276/32 277/28 273/23 271/31 472 | -------------------------------------------------------------------------------- /examples/maisel: -------------------------------------------------------------------------------- 1 | initFromFile "plane.off" 2 | setOutputFilename "examples/maisel.obj" 3 | setTextureFile "../res/maisel.png" 4 | addTextureRect "withoutbalc" 0. 0.625 1. 1. 5 | addTextureRect "withbalc" 0. 0.25 1. 0.625 6 | addTextureRect "longbalc" 0. 0. 0.488 0.21875 7 | addTextureRect "shortbalc" 0.4746 0. 0.6543 0.21875 8 | 9 | %% 10 | 11 | GlobalShape --> extrude(4.8) split("x") {~1: ColumnA | ~1: ColumnB }* ;; 12 | 13 | ColumnA --> split("y") {~0.4: WithBalc | ~0.4: WithoutBalc }* ;; 14 | ColumnB --> split("y") {~0.4: WithoutBalc | ~0.4: WithBalc }* ;; 15 | 16 | WithoutBalc --> selectFaces("z") setTexture("withoutbalc") ;; 17 | WithBalc --> selectFaces("z") setTexture("withbalc") 18 | split("x") {~56:Trash | ~200:Balcony | ~200:Balcony | ~56:Trash} ;; 19 | 20 | Balcony --> split("y") {~90: selectFaces("z") extrude(0.15) TextureBalc | ~100:Trash} ;; 21 | 22 | TextureBalc --> selectFaces("z") setTexture("longbalc") selectFaces("") 23 | selectFaces("x") setTexture("shortbalc") selectFaces("") 24 | selectFaces("ypos") removeFaces() ;; 25 | -------------------------------------------------------------------------------- /examples/maisel.mtl: -------------------------------------------------------------------------------- 1 | newmtl Texture 2 | map_Kd ../res/maisel.png 3 | -------------------------------------------------------------------------------- /examples/paper_example: -------------------------------------------------------------------------------- 1 | initFromFile "plane.off" 2 | 3 | %% 4 | 5 | Parcel --> split("x") {~1: extrude(15) Tower | ~1: GreenSpace | ~1: extrude(12) Tower} ;; 6 | 7 | Tower --> split("y") { 2:Base | {~0.4: Floor}* } ;; 8 | 9 | Floor --> translate(0.2, 0, 0) Floor2 ;; 10 | Floor --> translate(-0.2, 0, 0) Floor2 ;; 11 | 12 | Floor2 --> translate(0, 0, 0.2) ;; 13 | Floor2 --> translate(0, 0, -0.2) ;; 14 | -------------------------------------------------------------------------------- /examples/paper_example.off: -------------------------------------------------------------------------------- 1 | OFF 2 | 500 303 0 3 | -4 0 -1 4 | -1.33333 0 -1 5 | -4 0 1 6 | -1.33333 0 1 7 | -4 0 -1 8 | -4 2 -1 9 | -4 0 1 10 | -4 2 1 11 | -1.33333 0 1 12 | -1.33333 2 1 13 | -1.33333 0 -1 14 | -1.33333 2 -1 15 | -4.2 2 -0.8 16 | -4.2 2.39394 -0.8 17 | -4.2 2 1.2 18 | -4.2 2.39394 1.2 19 | -1.53333 2 1.2 20 | -1.53333 2.39394 1.2 21 | -1.53333 2 -0.8 22 | -1.53333 2.39394 -0.8 23 | -4.2 2.39394 -1.2 24 | -4.2 2.78788 -1.2 25 | -4.2 2.39394 0.8 26 | -4.2 2.78788 0.8 27 | -1.53333 2.39394 0.8 28 | -1.53333 2.78788 0.8 29 | -1.53333 2.39394 -1.2 30 | -1.53333 2.78788 -1.2 31 | -4.2 2.78788 -1.2 32 | -4.2 3.18182 -1.2 33 | -4.2 2.78788 0.8 34 | -4.2 3.18182 0.8 35 | -1.53333 2.78788 0.8 36 | -1.53333 3.18182 0.8 37 | -1.53333 2.78788 -1.2 38 | -1.53333 3.18182 -1.2 39 | -4.2 3.18182 -1.2 40 | -4.2 3.57576 -1.2 41 | -4.2 3.18182 0.8 42 | -4.2 3.57576 0.8 43 | -1.53333 3.18182 0.8 44 | -1.53333 3.57576 0.8 45 | -1.53333 3.18182 -1.2 46 | -1.53333 3.57576 -1.2 47 | -4.2 3.57576 -0.8 48 | -4.2 3.9697 -0.8 49 | -4.2 3.57576 1.2 50 | -4.2 3.9697 1.2 51 | -1.53333 3.57576 1.2 52 | -1.53333 3.9697 1.2 53 | -1.53333 3.57576 -0.8 54 | -1.53333 3.9697 -0.8 55 | -4.2 3.9697 -1.2 56 | -4.2 4.36364 -1.2 57 | -4.2 3.9697 0.8 58 | -4.2 4.36364 0.8 59 | -1.53333 3.9697 0.8 60 | -1.53333 4.36364 0.8 61 | -1.53333 3.9697 -1.2 62 | -1.53333 4.36364 -1.2 63 | -4.2 4.36364 -1.2 64 | -4.2 4.75758 -1.2 65 | -4.2 4.36364 0.8 66 | -4.2 4.75758 0.8 67 | -1.53333 4.36364 0.8 68 | -1.53333 4.75758 0.8 69 | -1.53333 4.36364 -1.2 70 | -1.53333 4.75758 -1.2 71 | -4.2 4.75758 -0.8 72 | -4.2 5.15152 -0.8 73 | -4.2 4.75758 1.2 74 | -4.2 5.15152 1.2 75 | -1.53333 4.75758 1.2 76 | -1.53333 5.15152 1.2 77 | -1.53333 4.75758 -0.8 78 | -1.53333 5.15152 -0.8 79 | -3.8 5.15152 -1.2 80 | -3.8 5.54545 -1.2 81 | -3.8 5.15152 0.8 82 | -3.8 5.54545 0.8 83 | -1.13333 5.15152 0.8 84 | -1.13333 5.54545 0.8 85 | -1.13333 5.15152 -1.2 86 | -1.13333 5.54545 -1.2 87 | -4.2 5.54545 -1.2 88 | -4.2 5.93939 -1.2 89 | -4.2 5.54545 0.8 90 | -4.2 5.93939 0.8 91 | -1.53333 5.54545 0.8 92 | -1.53333 5.93939 0.8 93 | -1.53333 5.54545 -1.2 94 | -1.53333 5.93939 -1.2 95 | -4.2 5.93939 -1.2 96 | -4.2 6.33333 -1.2 97 | -4.2 5.93939 0.8 98 | -4.2 6.33333 0.8 99 | -1.53333 5.93939 0.8 100 | -1.53333 6.33333 0.8 101 | -1.53333 5.93939 -1.2 102 | -1.53333 6.33333 -1.2 103 | -4.2 6.33333 -0.8 104 | -4.2 6.72727 -0.8 105 | -4.2 6.33333 1.2 106 | -4.2 6.72727 1.2 107 | -1.53333 6.33333 1.2 108 | -1.53333 6.72727 1.2 109 | -1.53333 6.33333 -0.8 110 | -1.53333 6.72727 -0.8 111 | -4.2 6.72727 -0.8 112 | -4.2 7.12121 -0.8 113 | -4.2 6.72727 1.2 114 | -4.2 7.12121 1.2 115 | -1.53333 6.72727 1.2 116 | -1.53333 7.12121 1.2 117 | -1.53333 6.72727 -0.8 118 | -1.53333 7.12121 -0.8 119 | -4.2 7.12121 -0.8 120 | -4.2 7.51515 -0.8 121 | -4.2 7.12121 1.2 122 | -4.2 7.51515 1.2 123 | -1.53333 7.12121 1.2 124 | -1.53333 7.51515 1.2 125 | -1.53333 7.12121 -0.8 126 | -1.53333 7.51515 -0.8 127 | -3.8 7.51515 -1.2 128 | -3.8 7.90909 -1.2 129 | -3.8 7.51515 0.8 130 | -3.8 7.90909 0.8 131 | -1.13333 7.51515 0.8 132 | -1.13333 7.90909 0.8 133 | -1.13333 7.51515 -1.2 134 | -1.13333 7.90909 -1.2 135 | -4.2 7.90909 -1.2 136 | -4.2 8.30303 -1.2 137 | -4.2 7.90909 0.8 138 | -4.2 8.30303 0.8 139 | -1.53333 7.90909 0.8 140 | -1.53333 8.30303 0.8 141 | -1.53333 7.90909 -1.2 142 | -1.53333 8.30303 -1.2 143 | -4.2 8.30303 -0.8 144 | -4.2 8.69697 -0.8 145 | -4.2 8.30303 1.2 146 | -4.2 8.69697 1.2 147 | -1.53333 8.30303 1.2 148 | -1.53333 8.69697 1.2 149 | -1.53333 8.30303 -0.8 150 | -1.53333 8.69697 -0.8 151 | -4.2 8.69697 -1.2 152 | -4.2 9.09091 -1.2 153 | -4.2 8.69697 0.8 154 | -4.2 9.09091 0.8 155 | -1.53333 8.69697 0.8 156 | -1.53333 9.09091 0.8 157 | -1.53333 8.69697 -1.2 158 | -1.53333 9.09091 -1.2 159 | -3.8 9.09091 -0.8 160 | -3.8 9.48485 -0.8 161 | -3.8 9.09091 1.2 162 | -3.8 9.48485 1.2 163 | -1.13333 9.09091 1.2 164 | -1.13333 9.48485 1.2 165 | -1.13333 9.09091 -0.8 166 | -1.13333 9.48485 -0.8 167 | -3.8 9.48485 -1.2 168 | -3.8 9.87879 -1.2 169 | -3.8 9.48485 0.8 170 | -3.8 9.87879 0.8 171 | -1.13333 9.48485 0.8 172 | -1.13333 9.87879 0.8 173 | -1.13333 9.48485 -1.2 174 | -1.13333 9.87879 -1.2 175 | -3.8 9.87879 -1.2 176 | -3.8 10.2727 -1.2 177 | -3.8 9.87879 0.8 178 | -3.8 10.2727 0.8 179 | -1.13333 9.87879 0.8 180 | -1.13333 10.2727 0.8 181 | -1.13333 9.87879 -1.2 182 | -1.13333 10.2727 -1.2 183 | -3.8 10.2727 -0.8 184 | -3.8 10.6667 -0.8 185 | -3.8 10.2727 1.2 186 | -3.8 10.6667 1.2 187 | -1.13333 10.2727 1.2 188 | -1.13333 10.6667 1.2 189 | -1.13333 10.2727 -0.8 190 | -1.13333 10.6667 -0.8 191 | -3.8 10.6667 -0.8 192 | -3.8 11.0606 -0.8 193 | -3.8 10.6667 1.2 194 | -3.8 11.0606 1.2 195 | -1.13333 10.6667 1.2 196 | -1.13333 11.0606 1.2 197 | -1.13333 10.6667 -0.8 198 | -1.13333 11.0606 -0.8 199 | -3.8 11.0606 -0.8 200 | -3.8 11.4545 -0.8 201 | -3.8 11.0606 1.2 202 | -3.8 11.4545 1.2 203 | -1.13333 11.0606 1.2 204 | -1.13333 11.4545 1.2 205 | -1.13333 11.0606 -0.8 206 | -1.13333 11.4545 -0.8 207 | -4.2 11.4545 -1.2 208 | -4.2 11.8485 -1.2 209 | -4.2 11.4545 0.8 210 | -4.2 11.8485 0.8 211 | -1.53333 11.4545 0.8 212 | -1.53333 11.8485 0.8 213 | -1.53333 11.4545 -1.2 214 | -1.53333 11.8485 -1.2 215 | -3.8 11.8485 -1.2 216 | -3.8 12.2424 -1.2 217 | -3.8 11.8485 0.8 218 | -3.8 12.2424 0.8 219 | -1.13333 11.8485 0.8 220 | -1.13333 12.2424 0.8 221 | -1.13333 11.8485 -1.2 222 | -1.13333 12.2424 -1.2 223 | -4.2 12.2424 -0.8 224 | -4.2 12.6364 -0.8 225 | -4.2 12.2424 1.2 226 | -4.2 12.6364 1.2 227 | -1.53333 12.2424 1.2 228 | -1.53333 12.6364 1.2 229 | -1.53333 12.2424 -0.8 230 | -1.53333 12.6364 -0.8 231 | -3.8 12.6364 -1.2 232 | -3.8 13.0303 -1.2 233 | -3.8 12.6364 0.8 234 | -3.8 13.0303 0.8 235 | -1.13333 12.6364 0.8 236 | -1.13333 13.0303 0.8 237 | -1.13333 12.6364 -1.2 238 | -1.13333 13.0303 -1.2 239 | -4.2 13.0303 -0.8 240 | -4.2 13.4242 -0.8 241 | -4.2 13.0303 1.2 242 | -4.2 13.4242 1.2 243 | -1.53333 13.0303 1.2 244 | -1.53333 13.4242 1.2 245 | -1.53333 13.0303 -0.8 246 | -1.53333 13.4242 -0.8 247 | -3.8 13.4242 -1.2 248 | -3.8 13.8182 -1.2 249 | -3.8 13.4242 0.8 250 | -3.8 13.8182 0.8 251 | -1.13333 13.4242 0.8 252 | -1.13333 13.8182 0.8 253 | -1.13333 13.4242 -1.2 254 | -1.13333 13.8182 -1.2 255 | -3.8 13.8182 -1.2 256 | -3.8 14.2121 -1.2 257 | -3.8 13.8182 0.8 258 | -3.8 14.2121 0.8 259 | -1.13333 13.8182 0.8 260 | -1.13333 14.2121 0.8 261 | -1.13333 13.8182 -1.2 262 | -1.13333 14.2121 -1.2 263 | -3.8 14.2121 -1.2 264 | -3.8 14.6061 -1.2 265 | -3.8 14.2121 0.8 266 | -3.8 14.6061 0.8 267 | -1.13333 14.2121 0.8 268 | -1.13333 14.6061 0.8 269 | -1.13333 14.2121 -1.2 270 | -1.13333 14.6061 -1.2 271 | -4.2 14.6061 -1.2 272 | -4.2 15 -1.2 273 | -4.2 14.6061 0.8 274 | -4.2 15 0.8 275 | -1.53333 14.6061 0.8 276 | -1.53333 15 0.8 277 | -1.53333 14.6061 -1.2 278 | -1.53333 15 -1.2 279 | -4.2 15 -1.2 280 | -4.2 15 0.8 281 | -1.53333 15 0.8 282 | -1.53333 15 -1.2 283 | -1.33333 0 -1 284 | 1.33333 0 -1 285 | -1.33333 0 1 286 | 1.33333 0 1 287 | 1.33333 0 -1 288 | 4 0 -1 289 | 1.33333 0 1 290 | 4 0 1 291 | 1.33333 0 -1 292 | 1.33333 2 -1 293 | 1.33333 0 1 294 | 1.33333 2 1 295 | 4 0 1 296 | 4 2 1 297 | 4 0 -1 298 | 4 2 -1 299 | 1.53333 2 -0.8 300 | 1.53333 2.4 -0.8 301 | 1.53333 2 1.2 302 | 1.53333 2.4 1.2 303 | 4.2 2 1.2 304 | 4.2 2.4 1.2 305 | 4.2 2 -0.8 306 | 4.2 2.4 -0.8 307 | 1.13333 2.4 -0.8 308 | 1.13333 2.8 -0.8 309 | 1.13333 2.4 1.2 310 | 1.13333 2.8 1.2 311 | 3.8 2.4 1.2 312 | 3.8 2.8 1.2 313 | 3.8 2.4 -0.8 314 | 3.8 2.8 -0.8 315 | 1.53333 2.8 -1.2 316 | 1.53333 3.2 -1.2 317 | 1.53333 2.8 0.8 318 | 1.53333 3.2 0.8 319 | 4.2 2.8 0.8 320 | 4.2 3.2 0.8 321 | 4.2 2.8 -1.2 322 | 4.2 3.2 -1.2 323 | 1.53333 3.2 -1.2 324 | 1.53333 3.6 -1.2 325 | 1.53333 3.2 0.8 326 | 1.53333 3.6 0.8 327 | 4.2 3.2 0.8 328 | 4.2 3.6 0.8 329 | 4.2 3.2 -1.2 330 | 4.2 3.6 -1.2 331 | 1.13333 3.6 -1.2 332 | 1.13333 4 -1.2 333 | 1.13333 3.6 0.8 334 | 1.13333 4 0.8 335 | 3.8 3.6 0.8 336 | 3.8 4 0.8 337 | 3.8 3.6 -1.2 338 | 3.8 4 -1.2 339 | 1.53333 4 -0.8 340 | 1.53333 4.4 -0.8 341 | 1.53333 4 1.2 342 | 1.53333 4.4 1.2 343 | 4.2 4 1.2 344 | 4.2 4.4 1.2 345 | 4.2 4 -0.8 346 | 4.2 4.4 -0.8 347 | 1.53333 4.4 -1.2 348 | 1.53333 4.8 -1.2 349 | 1.53333 4.4 0.8 350 | 1.53333 4.8 0.8 351 | 4.2 4.4 0.8 352 | 4.2 4.8 0.8 353 | 4.2 4.4 -1.2 354 | 4.2 4.8 -1.2 355 | 1.13333 4.8 -0.8 356 | 1.13333 5.2 -0.8 357 | 1.13333 4.8 1.2 358 | 1.13333 5.2 1.2 359 | 3.8 4.8 1.2 360 | 3.8 5.2 1.2 361 | 3.8 4.8 -0.8 362 | 3.8 5.2 -0.8 363 | 1.13333 5.2 -0.8 364 | 1.13333 5.6 -0.8 365 | 1.13333 5.2 1.2 366 | 1.13333 5.6 1.2 367 | 3.8 5.2 1.2 368 | 3.8 5.6 1.2 369 | 3.8 5.2 -0.8 370 | 3.8 5.6 -0.8 371 | 1.53333 5.6 -1.2 372 | 1.53333 6 -1.2 373 | 1.53333 5.6 0.8 374 | 1.53333 6 0.8 375 | 4.2 5.6 0.8 376 | 4.2 6 0.8 377 | 4.2 5.6 -1.2 378 | 4.2 6 -1.2 379 | 1.13333 6 -0.8 380 | 1.13333 6.4 -0.8 381 | 1.13333 6 1.2 382 | 1.13333 6.4 1.2 383 | 3.8 6 1.2 384 | 3.8 6.4 1.2 385 | 3.8 6 -0.8 386 | 3.8 6.4 -0.8 387 | 1.53333 6.4 -0.8 388 | 1.53333 6.8 -0.8 389 | 1.53333 6.4 1.2 390 | 1.53333 6.8 1.2 391 | 4.2 6.4 1.2 392 | 4.2 6.8 1.2 393 | 4.2 6.4 -0.8 394 | 4.2 6.8 -0.8 395 | 1.53333 6.8 -1.2 396 | 1.53333 7.2 -1.2 397 | 1.53333 6.8 0.8 398 | 1.53333 7.2 0.8 399 | 4.2 6.8 0.8 400 | 4.2 7.2 0.8 401 | 4.2 6.8 -1.2 402 | 4.2 7.2 -1.2 403 | 1.53333 7.2 -0.8 404 | 1.53333 7.6 -0.8 405 | 1.53333 7.2 1.2 406 | 1.53333 7.6 1.2 407 | 4.2 7.2 1.2 408 | 4.2 7.6 1.2 409 | 4.2 7.2 -0.8 410 | 4.2 7.6 -0.8 411 | 1.13333 7.6 -1.2 412 | 1.13333 8 -1.2 413 | 1.13333 7.6 0.8 414 | 1.13333 8 0.8 415 | 3.8 7.6 0.8 416 | 3.8 8 0.8 417 | 3.8 7.6 -1.2 418 | 3.8 8 -1.2 419 | 1.53333 8 -1.2 420 | 1.53333 8.4 -1.2 421 | 1.53333 8 0.8 422 | 1.53333 8.4 0.8 423 | 4.2 8 0.8 424 | 4.2 8.4 0.8 425 | 4.2 8 -1.2 426 | 4.2 8.4 -1.2 427 | 1.53333 8.4 -0.8 428 | 1.53333 8.8 -0.8 429 | 1.53333 8.4 1.2 430 | 1.53333 8.8 1.2 431 | 4.2 8.4 1.2 432 | 4.2 8.8 1.2 433 | 4.2 8.4 -0.8 434 | 4.2 8.8 -0.8 435 | 1.13333 8.8 -1.2 436 | 1.13333 9.2 -1.2 437 | 1.13333 8.8 0.8 438 | 1.13333 9.2 0.8 439 | 3.8 8.8 0.8 440 | 3.8 9.2 0.8 441 | 3.8 8.8 -1.2 442 | 3.8 9.2 -1.2 443 | 1.53333 9.2 -1.2 444 | 1.53333 9.6 -1.2 445 | 1.53333 9.2 0.8 446 | 1.53333 9.6 0.8 447 | 4.2 9.2 0.8 448 | 4.2 9.6 0.8 449 | 4.2 9.2 -1.2 450 | 4.2 9.6 -1.2 451 | 1.53333 9.6 -1.2 452 | 1.53333 10 -1.2 453 | 1.53333 9.6 0.8 454 | 1.53333 10 0.8 455 | 4.2 9.6 0.8 456 | 4.2 10 0.8 457 | 4.2 9.6 -1.2 458 | 4.2 10 -1.2 459 | 1.13333 10 -1.2 460 | 1.13333 10.4 -1.2 461 | 1.13333 10 0.8 462 | 1.13333 10.4 0.8 463 | 3.8 10 0.8 464 | 3.8 10.4 0.8 465 | 3.8 10 -1.2 466 | 3.8 10.4 -1.2 467 | 1.53333 10.4 -0.8 468 | 1.53333 10.8 -0.8 469 | 1.53333 10.4 1.2 470 | 1.53333 10.8 1.2 471 | 4.2 10.4 1.2 472 | 4.2 10.8 1.2 473 | 4.2 10.4 -0.8 474 | 4.2 10.8 -0.8 475 | 1.53333 10.8 -1.2 476 | 1.53333 11.2 -1.2 477 | 1.53333 10.8 0.8 478 | 1.53333 11.2 0.8 479 | 4.2 10.8 0.8 480 | 4.2 11.2 0.8 481 | 4.2 10.8 -1.2 482 | 4.2 11.2 -1.2 483 | 1.13333 11.2 -0.8 484 | 1.13333 11.6 -0.8 485 | 1.13333 11.2 1.2 486 | 1.13333 11.6 1.2 487 | 3.8 11.2 1.2 488 | 3.8 11.6 1.2 489 | 3.8 11.2 -0.8 490 | 3.8 11.6 -0.8 491 | 1.13333 11.6 -0.8 492 | 1.13333 12 -0.8 493 | 1.13333 11.6 1.2 494 | 1.13333 12 1.2 495 | 3.8 11.6 1.2 496 | 3.8 12 1.2 497 | 3.8 11.6 -0.8 498 | 3.8 12 -0.8 499 | 1.13333 12 -0.8 500 | 1.13333 12 1.2 501 | 3.8 12 1.2 502 | 3.8 12 -0.8 503 | 4 0 2 3 1 504 | 4 4 6 7 5 505 | 4 6 8 9 7 506 | 4 8 10 11 9 507 | 4 10 4 5 11 508 | 4 5 7 9 11 509 | 4 12 14 15 13 510 | 4 14 16 17 15 511 | 4 16 18 19 17 512 | 4 18 12 13 19 513 | 4 13 15 17 19 514 | 4 20 22 23 21 515 | 4 22 24 25 23 516 | 4 24 26 27 25 517 | 4 26 20 21 27 518 | 4 21 23 25 27 519 | 4 28 30 31 29 520 | 4 30 32 33 31 521 | 4 32 34 35 33 522 | 4 34 28 29 35 523 | 4 29 31 33 35 524 | 4 36 38 39 37 525 | 4 38 40 41 39 526 | 4 40 42 43 41 527 | 4 42 36 37 43 528 | 4 37 39 41 43 529 | 4 44 46 47 45 530 | 4 46 48 49 47 531 | 4 48 50 51 49 532 | 4 50 44 45 51 533 | 4 45 47 49 51 534 | 4 52 54 55 53 535 | 4 54 56 57 55 536 | 4 56 58 59 57 537 | 4 58 52 53 59 538 | 4 53 55 57 59 539 | 4 60 62 63 61 540 | 4 62 64 65 63 541 | 4 64 66 67 65 542 | 4 66 60 61 67 543 | 4 61 63 65 67 544 | 4 68 70 71 69 545 | 4 70 72 73 71 546 | 4 72 74 75 73 547 | 4 74 68 69 75 548 | 4 69 71 73 75 549 | 4 76 78 79 77 550 | 4 78 80 81 79 551 | 4 80 82 83 81 552 | 4 82 76 77 83 553 | 4 77 79 81 83 554 | 4 84 86 87 85 555 | 4 86 88 89 87 556 | 4 88 90 91 89 557 | 4 90 84 85 91 558 | 4 85 87 89 91 559 | 4 92 94 95 93 560 | 4 94 96 97 95 561 | 4 96 98 99 97 562 | 4 98 92 93 99 563 | 4 93 95 97 99 564 | 4 100 102 103 101 565 | 4 102 104 105 103 566 | 4 104 106 107 105 567 | 4 106 100 101 107 568 | 4 101 103 105 107 569 | 4 108 110 111 109 570 | 4 110 112 113 111 571 | 4 112 114 115 113 572 | 4 114 108 109 115 573 | 4 109 111 113 115 574 | 4 116 118 119 117 575 | 4 118 120 121 119 576 | 4 120 122 123 121 577 | 4 122 116 117 123 578 | 4 117 119 121 123 579 | 4 124 126 127 125 580 | 4 126 128 129 127 581 | 4 128 130 131 129 582 | 4 130 124 125 131 583 | 4 125 127 129 131 584 | 4 132 134 135 133 585 | 4 134 136 137 135 586 | 4 136 138 139 137 587 | 4 138 132 133 139 588 | 4 133 135 137 139 589 | 4 140 142 143 141 590 | 4 142 144 145 143 591 | 4 144 146 147 145 592 | 4 146 140 141 147 593 | 4 141 143 145 147 594 | 4 148 150 151 149 595 | 4 150 152 153 151 596 | 4 152 154 155 153 597 | 4 154 148 149 155 598 | 4 149 151 153 155 599 | 4 156 158 159 157 600 | 4 158 160 161 159 601 | 4 160 162 163 161 602 | 4 162 156 157 163 603 | 4 157 159 161 163 604 | 4 164 166 167 165 605 | 4 166 168 169 167 606 | 4 168 170 171 169 607 | 4 170 164 165 171 608 | 4 165 167 169 171 609 | 4 172 174 175 173 610 | 4 174 176 177 175 611 | 4 176 178 179 177 612 | 4 178 172 173 179 613 | 4 173 175 177 179 614 | 4 180 182 183 181 615 | 4 182 184 185 183 616 | 4 184 186 187 185 617 | 4 186 180 181 187 618 | 4 181 183 185 187 619 | 4 188 190 191 189 620 | 4 190 192 193 191 621 | 4 192 194 195 193 622 | 4 194 188 189 195 623 | 4 189 191 193 195 624 | 4 196 198 199 197 625 | 4 198 200 201 199 626 | 4 200 202 203 201 627 | 4 202 196 197 203 628 | 4 197 199 201 203 629 | 4 204 206 207 205 630 | 4 206 208 209 207 631 | 4 208 210 211 209 632 | 4 210 204 205 211 633 | 4 205 207 209 211 634 | 4 212 214 215 213 635 | 4 214 216 217 215 636 | 4 216 218 219 217 637 | 4 218 212 213 219 638 | 4 213 215 217 219 639 | 4 220 222 223 221 640 | 4 222 224 225 223 641 | 4 224 226 227 225 642 | 4 226 220 221 227 643 | 4 221 223 225 227 644 | 4 228 230 231 229 645 | 4 230 232 233 231 646 | 4 232 234 235 233 647 | 4 234 228 229 235 648 | 4 229 231 233 235 649 | 4 236 238 239 237 650 | 4 238 240 241 239 651 | 4 240 242 243 241 652 | 4 242 236 237 243 653 | 4 237 239 241 243 654 | 4 244 246 247 245 655 | 4 246 248 249 247 656 | 4 248 250 251 249 657 | 4 250 244 245 251 658 | 4 245 247 249 251 659 | 4 252 254 255 253 660 | 4 254 256 257 255 661 | 4 256 258 259 257 662 | 4 258 252 253 259 663 | 4 253 255 257 259 664 | 4 260 262 263 261 665 | 4 262 264 265 263 666 | 4 264 266 267 265 667 | 4 266 260 261 267 668 | 4 261 263 265 267 669 | 4 268 270 271 269 670 | 4 270 272 273 271 671 | 4 272 274 275 273 672 | 4 274 268 269 275 673 | 4 269 271 273 275 674 | 4 280 282 283 281 675 | 4 284 286 287 285 676 | 4 288 290 291 289 677 | 4 290 292 293 291 678 | 4 292 294 295 293 679 | 4 294 288 289 295 680 | 4 289 291 293 295 681 | 4 296 298 299 297 682 | 4 298 300 301 299 683 | 4 300 302 303 301 684 | 4 302 296 297 303 685 | 4 297 299 301 303 686 | 4 304 306 307 305 687 | 4 306 308 309 307 688 | 4 308 310 311 309 689 | 4 310 304 305 311 690 | 4 305 307 309 311 691 | 4 312 314 315 313 692 | 4 314 316 317 315 693 | 4 316 318 319 317 694 | 4 318 312 313 319 695 | 4 313 315 317 319 696 | 4 320 322 323 321 697 | 4 322 324 325 323 698 | 4 324 326 327 325 699 | 4 326 320 321 327 700 | 4 321 323 325 327 701 | 4 328 330 331 329 702 | 4 330 332 333 331 703 | 4 332 334 335 333 704 | 4 334 328 329 335 705 | 4 329 331 333 335 706 | 4 336 338 339 337 707 | 4 338 340 341 339 708 | 4 340 342 343 341 709 | 4 342 336 337 343 710 | 4 337 339 341 343 711 | 4 344 346 347 345 712 | 4 346 348 349 347 713 | 4 348 350 351 349 714 | 4 350 344 345 351 715 | 4 345 347 349 351 716 | 4 352 354 355 353 717 | 4 354 356 357 355 718 | 4 356 358 359 357 719 | 4 358 352 353 359 720 | 4 353 355 357 359 721 | 4 360 362 363 361 722 | 4 362 364 365 363 723 | 4 364 366 367 365 724 | 4 366 360 361 367 725 | 4 361 363 365 367 726 | 4 368 370 371 369 727 | 4 370 372 373 371 728 | 4 372 374 375 373 729 | 4 374 368 369 375 730 | 4 369 371 373 375 731 | 4 376 378 379 377 732 | 4 378 380 381 379 733 | 4 380 382 383 381 734 | 4 382 376 377 383 735 | 4 377 379 381 383 736 | 4 384 386 387 385 737 | 4 386 388 389 387 738 | 4 388 390 391 389 739 | 4 390 384 385 391 740 | 4 385 387 389 391 741 | 4 392 394 395 393 742 | 4 394 396 397 395 743 | 4 396 398 399 397 744 | 4 398 392 393 399 745 | 4 393 395 397 399 746 | 4 400 402 403 401 747 | 4 402 404 405 403 748 | 4 404 406 407 405 749 | 4 406 400 401 407 750 | 4 401 403 405 407 751 | 4 408 410 411 409 752 | 4 410 412 413 411 753 | 4 412 414 415 413 754 | 4 414 408 409 415 755 | 4 409 411 413 415 756 | 4 416 418 419 417 757 | 4 418 420 421 419 758 | 4 420 422 423 421 759 | 4 422 416 417 423 760 | 4 417 419 421 423 761 | 4 424 426 427 425 762 | 4 426 428 429 427 763 | 4 428 430 431 429 764 | 4 430 424 425 431 765 | 4 425 427 429 431 766 | 4 432 434 435 433 767 | 4 434 436 437 435 768 | 4 436 438 439 437 769 | 4 438 432 433 439 770 | 4 433 435 437 439 771 | 4 440 442 443 441 772 | 4 442 444 445 443 773 | 4 444 446 447 445 774 | 4 446 440 441 447 775 | 4 441 443 445 447 776 | 4 448 450 451 449 777 | 4 450 452 453 451 778 | 4 452 454 455 453 779 | 4 454 448 449 455 780 | 4 449 451 453 455 781 | 4 456 458 459 457 782 | 4 458 460 461 459 783 | 4 460 462 463 461 784 | 4 462 456 457 463 785 | 4 457 459 461 463 786 | 4 464 466 467 465 787 | 4 466 468 469 467 788 | 4 468 470 471 469 789 | 4 470 464 465 471 790 | 4 465 467 469 471 791 | 4 472 474 475 473 792 | 4 474 476 477 475 793 | 4 476 478 479 477 794 | 4 478 472 473 479 795 | 4 473 475 477 479 796 | 4 480 482 483 481 797 | 4 482 484 485 483 798 | 4 484 486 487 485 799 | 4 486 480 481 487 800 | 4 481 483 485 487 801 | 4 488 490 491 489 802 | 4 490 492 493 491 803 | 4 492 494 495 493 804 | 4 494 488 489 495 805 | 4 489 491 493 495 806 | -------------------------------------------------------------------------------- /examples/town: -------------------------------------------------------------------------------- 1 | initFromRect 65 65 2 | setOutputFilename "examples/town.obj" 3 | setRoofZoom 2 4 | setRoofTexture "../res/roof_south.jpg" 5 | setTextureFile "../res/house_south.png" 6 | addTextureRect "garage" 0. 0. 0.5 0.45 7 | addTextureRect "wall" 0.5 0. 1. 0.5 8 | addTextureRect "window" 0. 0.5 0.5 1. 9 | addTextureRect "door" 0.5 0.5. 1. 1. 10 | addTextureRect "road" 0.82 0.75. 0.82001 0.75001 11 | 12 | %% 13 | 14 | Village --> split("x") {~10:VillageX | ~3:Road}* ;; 15 | VillageX --> split("z") {~10:House | ~3:Road}* ;; 16 | 17 | Road --> selectFaces("ypos") setTexture("road") ;; 18 | 19 | House --> Road ;; 20 | House 3 --> createRoof(20,0.3) split("x") {~1: Garage | ~2: Center1 | ~1: EdgeZ } ;; 21 | 22 | Garage --> split("z") {2.5: GrowLevel roof() TextureGarage | ~1: EdgeZ} ;; 23 | 24 | Center1 --> split("z") {~1:Front | ~2: GrowLevel Center | ~1: EdgeX} ;; 25 | 26 | Front --> split("x") {~1: GrowLevel roof() TextureEntrance Room | ~1: Edge} ;; 27 | 28 | EdgeX --> split("x") {~2.5: Edge}* ;; 29 | EdgeZ --> split("z") {~2.5: Edge}* ;; 30 | RoomX --> split("x") {~2.5: Room}* ;; 31 | 32 | Edge --> Road ;; 33 | Edge --> Room ;; 34 | 35 | Room --> GrowLevel roof() TextureWall ;; 36 | Room --> GrowLevel TextureWall Room ;; 37 | 38 | Center --> split("z") {~2.5:RoomX}* ;; 39 | 40 | TextureGarage --> selectFaces("zneg") setTexture("garage") 41 | selectFaces("") selectFaces("zpos") selectFaces("x") setTexture("wall") ;; 42 | 43 | TextureEntrance --> TextureWall selectFaces("") selectFaces("zneg") setTexture("door") ;; 44 | 45 | TextureWall --> selectFaces("all") setTexture("wall") PaintWindow ;; 46 | PaintWindow --> selectFaces("z") setTexture("window") ;; 47 | PaintWindow --> selectFaces("x") setTexture("window") ;; 48 | PaintWindow 2 --> selectFaces("all") setTexture("window") ;; 49 | 50 | GrowLevel --> selectFaces("") selectFaces("ypos") extrude(2.5) ;; 51 | 52 | setRecDepth GrowLevel 7 53 | fallback GrowLevel --> roof() ;; 54 | -------------------------------------------------------------------------------- /examples/town.mtl: -------------------------------------------------------------------------------- 1 | newmtl Texture 2 | map_Kd ../res/house_south.png 3 | newmtl RoofTexture 4 | map_Kd ../res/roof_south.jpg 5 | -------------------------------------------------------------------------------- /examples/town_without_roof: -------------------------------------------------------------------------------- 1 | initFromRect 520 520 2 | setOutputFilename "examples/town_without_roof.obj" 3 | setTextureFile "../res/town_custom_roof.png" 4 | addTextureRect "roof" 0. 0. 0.5 0.45 5 | addTextureRect "wall" 0.5 0. 1. 0.5 6 | addTextureRect "window" 0. 0.51 0.5 1. 7 | addTextureRect "door" 0.51 0.5. 1. 1. 8 | addTextureRect "road" 0.82 0.75. 0.82001 0.75001 9 | 10 | %% 11 | 12 | Village --> split("x") {~10:VillageX | ~3:Road}* ;; 13 | VillageX --> split("z") {~10:House | ~3:Road}* ;; 14 | 15 | Road --> selectFaces("ypos") setTexture("road") ;; 16 | 17 | House --> Road ;; 18 | House 3 --> split("x") {~1: Garage | ~2: Center1 | ~1: EdgeZ } ;; 19 | 20 | Garage --> split("z") {2.5: GrowLevel Roof TextureGarage | ~1: EdgeZ} ;; 21 | 22 | Center1 --> split("z") {~1:Front | ~2: GrowLevel Center | ~1: EdgeX} ;; 23 | 24 | Front --> split("x") {~1: GrowLevel Roof TextureEntrance Room | ~1: Edge} ;; 25 | 26 | EdgeX --> split("x") {~2.5: Edge}* ;; 27 | EdgeZ --> split("z") {~2.5: Edge}* ;; 28 | RoomX --> split("x") {~2.5: Room}* ;; 29 | 30 | Edge --> Road ;; 31 | Edge --> Room ;; 32 | 33 | Room --> GrowLevel Roof TextureWall ;; 34 | Room --> GrowLevel TextureWall Room ;; 35 | 36 | Center --> split("z") {~2.5:RoomX}* ;; 37 | 38 | TextureGarage --> selectFaces("zneg") setTexture("window") 39 | selectFaces("") selectFaces("zpos") selectFaces("x") setTexture("wall") ;; 40 | 41 | TextureEntrance --> TextureWall selectFaces("") selectFaces("zneg") setTexture("door") ;; 42 | 43 | TextureWall --> selectFaces("x") selectFaces("z") setTexture("wall") PaintWindow ;; 44 | PaintWindow --> selectFaces("z") setTexture("window") ;; 45 | PaintWindow --> selectFaces("x") setTexture("window") ;; 46 | PaintWindow 2 --> selectFaces("x") selectFaces("z") setTexture("window") ;; 47 | 48 | GrowLevel --> selectFaces("") selectFaces("ypos") extrude(2.5) selectFaces("") ;; 49 | 50 | Roof --> selectFaces("") selectFaces("ypos") setTexture("roof") selectFaces("") ;; 51 | 52 | setRecDepth GrowLevel 9 53 | fallback GrowLevel --> Roof ;; 54 | -------------------------------------------------------------------------------- /mview: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvallet/CGA_interpreter/c76e15e06057cfd74b3d097c0d76286ce071c7ec/mview -------------------------------------------------------------------------------- /plane.off: -------------------------------------------------------------------------------- 1 | OFF 2 | 4 1 0 3 | -4.0000000000000000 0.0000000000000000 -1.0000000000000000 4 | -4.0000000000000000 0.0000000000000000 1.0000000000000000 5 | 4.0000000000000000 0.0000000000000000 1.0000000000000000 6 | 4.0000000000000000 0.0000000000000000 -1.0000000000000000 7 | 4 0 1 2 3 8 | -------------------------------------------------------------------------------- /report.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvallet/CGA_interpreter/c76e15e06057cfd74b3d097c0d76286ce071c7ec/report.pdf -------------------------------------------------------------------------------- /res/house_south.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvallet/CGA_interpreter/c76e15e06057cfd74b3d097c0d76286ce071c7ec/res/house_south.png -------------------------------------------------------------------------------- /res/maisel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvallet/CGA_interpreter/c76e15e06057cfd74b3d097c0d76286ce071c7ec/res/maisel.png -------------------------------------------------------------------------------- /res/roof_south.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvallet/CGA_interpreter/c76e15e06057cfd74b3d097c0d76286ce071c7ec/res/roof_south.jpg -------------------------------------------------------------------------------- /res/town_custom_roof.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvallet/CGA_interpreter/c76e15e06057cfd74b3d097c0d76286ce071c7ec/res/town_custom_roof.png -------------------------------------------------------------------------------- /src/actions/actions.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include 4 | #include "actions_scanner_internal.h" 5 | #include "actions_parser.h" 6 | #include "../rule.h" 7 | 8 | typedef ACT::ACT_Parser::token token; 9 | 10 | #define YY_NO_UNISTD_H 11 | int param_count = 0; 12 | int pattern_count = 0; 13 | %} 14 | 15 | %option prefix="act" 16 | %option outfile="actions_scanner.cpp" 17 | %option debug 18 | %option noyywrap 19 | %option c++ 20 | %option yyclass="ACT::ACT_Scanner" 21 | 22 | %x PARAM 23 | %x PATTERN 24 | %x REMAINING 25 | 26 | %% 27 | 28 | [ \r\t\n]* ; 29 | \( { param_count = 1; BEGIN(PARAM); return '(';} 30 | \( { param_count++; return '('; } 31 | \) { param_count--; 32 | if (param_count == 0) { 33 | BEGIN(INITIAL); 34 | } 35 | return ')'; 36 | } 37 | \"[^\"]*\" { yylval->sval = strdup(&yytext[1]); 38 | yylval->sval[strlen(yylval->sval) - 1] = '\0'; 39 | return token::STRING;} 40 | -?[0-9]+\.?[0-9]* { yylval->dval = atof(yytext); return token::DOUBLE;} 41 | \, { return ',';} 42 | translate { return token::TRANSLATE; } 43 | extrude { return token::EXTRUDE; } 44 | split { return token::SPLIT; } 45 | selectFaces { return token::SELECT_FACES; } 46 | setTexture { return token::SET_TEXTURE; } 47 | removeFaces { return token::REMOVE_FACES; } 48 | roof { return token::ROOF; } 49 | createRoof { return token::CREATE_ROOF; } 50 | \{ { pattern_count = 1; BEGIN(PATTERN); yylval->sval = strdup(yytext); return token::BEG_PTRN;} 51 | \{ { pattern_count++; yylval->sval = strdup(yytext); return token::CODE; } 52 | \}\* { pattern_count--; yylval->sval = strdup(yytext); 53 | if (pattern_count == 0) {BEGIN(INITIAL); return token::END_PTRN;} 54 | else return token::CODE; 55 | } 56 | \} { pattern_count--; yylval->sval = strdup(yytext); 57 | if (pattern_count == 0) {BEGIN(INITIAL); return token::END_PTRN;} 58 | else return token::CODE; 59 | } 60 | [^\{\}]* { yylval->sval = strdup(yytext); return token::CODE;} 61 | [a-zA-Z][a-zA-Z0-9]* { yylval->sval = strdup(yytext); 62 | if (RuleNames::getInstance().isRule(yytext)) { 63 | BEGIN(REMAINING); 64 | return token::RULE; 65 | } 66 | else return token::DEADRULE; 67 | } 68 | .* { yylval->sval = strdup(yytext); return token::ACTIONS;} 69 | 70 | %% 71 | -------------------------------------------------------------------------------- /src/actions/actions.y: -------------------------------------------------------------------------------- 1 | %skeleton "lalr1.cc" 2 | %require "3.0" 3 | %debug 4 | %defines "actions_parser.h" 5 | %define api.namespace{ACT} 6 | %define api.prefix {act} 7 | %define parser_class_name {ACT_Parser} 8 | 9 | %code requires{ 10 | namespace ACT { 11 | class ACT_Scanner; 12 | class ShapeTree; 13 | } 14 | } 15 | 16 | %parse-param { ACT_Scanner &scanner } 17 | %parse-param { ShapeTree &st } 18 | 19 | %code{ 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "actions_scanner.h" 26 | #include "../shape_tree.h" 27 | 28 | #undef yylex 29 | #define yylex scanner.actlex 30 | 31 | namespace ACT { 32 | std::string toStr(char* ptr); 33 | } 34 | } 35 | 36 | %output "actions_parser.cpp" 37 | 38 | %union { 39 | double dval; 40 | char* sval; 41 | } 42 | 43 | %token STRING 44 | %token CODE 45 | %token DOUBLE 46 | %token TRANSLATE 47 | %token EXTRUDE 48 | %token SPLIT 49 | %token SELECT_FACES 50 | %token SET_TEXTURE 51 | %token REMOVE_FACES 52 | %token ROOF 53 | %token CREATE_ROOF 54 | %token BEG_PTRN 55 | %token END_PTRN 56 | %token RULE 57 | %token DEADRULE 58 | %token ACTIONS 59 | 60 | %type code 61 | 62 | %% 63 | %start actions; 64 | actions: 65 | actions action 66 | | action 67 | ; 68 | 69 | action: 70 | translate 71 | | extrude 72 | | split 73 | | setTexture 74 | | selectFaces 75 | | removeFaces 76 | | createRoof 77 | | ROOF '(' ')' {st.addToRoof();} 78 | | RULE {st.addToRule(toStr($1));} 79 | | RULE ACTIONS {st.addToRule(toStr($1),toStr($2));} 80 | | DEADRULE 81 | ; 82 | 83 | code: 84 | code CODE {char *ss = (char *) malloc (strlen($1) + strlen($2) + 1); 85 | strcpy(ss,$1); free($1); 86 | strcat(ss,$2); free($2); 87 | $$ = ss; } 88 | | CODE {$$ = strdup($1); free($1);} 89 | ; 90 | 91 | translate: 92 | TRANSLATE '(' DOUBLE ',' DOUBLE ',' DOUBLE ')' {st.translate($3,$5,$7);} 93 | ; 94 | 95 | extrude: 96 | EXTRUDE '(' DOUBLE ')' {st.extrude($3);} 97 | ; 98 | 99 | split: 100 | SPLIT '(' STRING ')' BEG_PTRN code END_PTRN 101 | { char axis = $3[0]; 102 | st.split(axis, toStr($5) + toStr($6) + toStr($7)); 103 | } 104 | 105 | ; 106 | 107 | setTexture: 108 | SET_TEXTURE '(' STRING ')' { st.setTexture(toStr($3));} 109 | ; 110 | 111 | selectFaces: 112 | SELECT_FACES '(' STRING ')' { st.selectFaces(toStr($3));} 113 | ; 114 | 115 | removeFaces: 116 | REMOVE_FACES '(' ')' { st.removeFaces();} 117 | ; 118 | 119 | createRoof: 120 | CREATE_ROOF '(' DOUBLE ',' DOUBLE ')' { st.createRoof($3, $5);} 121 | ; 122 | 123 | %% 124 | 125 | void ACT::ACT_Parser::error( const std::string &err_message ) { 126 | std::cerr << "Actions: Error: " << err_message << "\n"; 127 | } 128 | 129 | std::string ACT::toStr(char* ptr) { 130 | std::string ret = (ptr != NULL) ? std::string(ptr, (strlen(ptr))) : std::string(""); 131 | delete[] ptr; // Delete memory allocated by lexer. 132 | return ret; 133 | } 134 | -------------------------------------------------------------------------------- /src/actions/actions_scanner.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define yyFlexLexer actFlexLexer 4 | #include 5 | #undef yyFlexLexer 6 | 7 | #include "actions_scanner_internal.h" 8 | -------------------------------------------------------------------------------- /src/actions/actions_scanner_internal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "actions_parser.h" 4 | 5 | namespace ACT { 6 | 7 | class ACT_Scanner : public actFlexLexer { 8 | public: 9 | ACT_Scanner(std::istream *in) : actFlexLexer(in), yylval( nullptr ){}; 10 | 11 | int yylex(ACT::ACT_Parser::semantic_type * const lval) { 12 | yylval = lval; 13 | return( yylex() ); 14 | } 15 | 16 | private: 17 | int yylex(); 18 | ACT::ACT_Parser::semantic_type *yylval; 19 | }; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/cgacode/cgacode.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include "cgacode_scanner_internal.h" 4 | #include "cgacode_parser.h" 5 | 6 | typedef CC::CC_Parser::token token; 7 | 8 | #define YY_NO_UNISTD_H 9 | 10 | namespace CC { 11 | int line_num = 1; 12 | int param_count = 0; 13 | } 14 | %} 15 | 16 | %option prefix="cc" 17 | %option outfile="cgacode_scanner.cpp" 18 | %option debug 19 | %option noyywrap 20 | %option c++ 21 | %option yyclass="CC::CC_Scanner" 22 | 23 | %x RULES 24 | %x RULEBODY 25 | 26 | %% 27 | 28 | [ \r\t]* ; 29 | initFromFile { return token::INIT_FROM_FILE;} 30 | initFromRect { return token::INIT_FROM_RECT;} 31 | setOutputFilename { return token::SET_OUTPUT_FILENAME;} 32 | setTextureFile { return token::SET_TEXTURE_FILE;} 33 | addTextureRect { return token::ADD_TEXTURE_RECT;} 34 | setRoofZoom { return token::SET_ROOF_ZOOM;} 35 | setRoofTexture { return token::SET_ROOF_TEXTURE;} 36 | \"[^\n"]*\" { yylval->sval = strdup(&yytext[1]); 37 | yylval->sval[strlen(yylval->sval) - 1] = '\0'; 38 | return token::STRING;} 39 | [0-9]+\.?[0-9]* { yylval->fval = atof(yytext); return token::DOUBLE; } 40 | "%%" { BEGIN(RULES); return token::SEPARATOR; } 41 | setRecDepth { return token::SET_REC_DEPTH;} 42 | fallback { return token::FALLBACK;} 43 | [a-zA-Z][a-zA-Z0-9]* { 44 | yylval->sval = strdup(yytext); return token::RULE_NAME;} 45 | [0-9]+\.?[0-9]* { 46 | yylval->fval = atof(yytext); return token::WEIGHT;} 47 | "-->" { BEGIN(RULEBODY); return token::RULE;} 48 | ";;" { BEGIN(RULES);} 49 | [^;]* { yylval->sval = strdup(yytext); return token::RULE_BODY;} 50 | \n { CC::line_num++;} 51 | %% 52 | -------------------------------------------------------------------------------- /src/cgacode/cgacode.y: -------------------------------------------------------------------------------- 1 | %skeleton "lalr1.cc" 2 | %require "3.0" 3 | %debug 4 | %defines "cgacode_parser.h" 5 | %define api.namespace{CC} 6 | %define api.prefix {cc} 7 | %define parser_class_name {CC_Parser} 8 | 9 | %code requires{ 10 | namespace CC { 11 | class CC_Scanner; 12 | class CC_Driver; 13 | } 14 | } 15 | 16 | %parse-param { CC_Scanner &scanner } 17 | %parse-param { CC_Driver &driver } 18 | 19 | %code{ 20 | #include 21 | #include 22 | #include 23 | 24 | #include "cgacode_scanner.h" 25 | #include "cgacode_driver.h" 26 | 27 | #undef yylex 28 | #define yylex scanner.cclex 29 | 30 | namespace CC { 31 | extern int line_num; 32 | std::string toStr(char* ptr); 33 | } 34 | } 35 | 36 | %output "cgacode_parser.cpp" 37 | 38 | %union { 39 | float fval; 40 | int ival; 41 | char* sval; 42 | } 43 | 44 | %token INIT_FROM_FILE 45 | %token INIT_FROM_RECT 46 | %token SET_OUTPUT_FILENAME 47 | %token SET_TEXTURE_FILE 48 | %token ADD_TEXTURE_RECT 49 | %token SET_ROOF_ZOOM 50 | %token SET_ROOF_TEXTURE 51 | %token SEPARATOR 52 | %token SET_REC_DEPTH 53 | %token FALLBACK 54 | %token RULE_NAME 55 | %token WEIGHT 56 | %token RULE 57 | %token RULE_BODY 58 | %token STRING 59 | %token DOUBLE 60 | 61 | %% 62 | %start skeleton; 63 | skeleton: 64 | commands SEPARATOR rules 65 | ; 66 | 67 | commands: 68 | commands command 69 | | command 70 | ; 71 | 72 | command: 73 | INIT_FROM_FILE STRING {driver.initFromFile(toStr($2));} 74 | | INIT_FROM_RECT DOUBLE DOUBLE {driver.initFromRect($2,$3);} 75 | | SET_OUTPUT_FILENAME STRING {driver.setOutputFilename(toStr($2));} 76 | | SET_TEXTURE_FILE STRING {driver.setTextureFile(toStr($2));} 77 | | ADD_TEXTURE_RECT STRING DOUBLE DOUBLE DOUBLE DOUBLE 78 | {driver.addTextureRect(toStr($2), $3, $4, $5, $6);} 79 | | SET_ROOF_ZOOM DOUBLE {driver.setRoofZoom($2);} 80 | | SET_ROOF_TEXTURE STRING {driver.setRoofTexture(toStr($2));} 81 | ; 82 | 83 | rules: 84 | rules rule 85 | | rule 86 | ; 87 | 88 | rule: 89 | SET_REC_DEPTH RULE_NAME WEIGHT {driver.setRecDepth(toStr($2), $3);} 90 | | FALLBACK RULE_NAME RULE RULE_BODY {driver.setFallback(toStr($2), toStr($4));} 91 | | rule_declaration 92 | ; 93 | 94 | rule_declaration: 95 | RULE_NAME WEIGHT RULE RULE_BODY {driver.addRule(toStr($1), $2, toStr($4));} 96 | | RULE_NAME RULE RULE_BODY {driver.addRule(toStr($1), 1, toStr($3));} 97 | ; 98 | 99 | %% 100 | 101 | void CC::CC_Parser::error( const std::string &err_message ) { 102 | std::cerr << "CGA Code : error: " << err_message << " Line: " << CC::line_num << "\n"; 103 | } 104 | 105 | std::string CC::toStr(char* ptr) { 106 | std::string ret = (ptr != NULL) ? std::string(ptr, (strlen(ptr))) : std::string(""); 107 | delete[] ptr; // Delete memory allocated by lexer. 108 | return ret; 109 | } 110 | -------------------------------------------------------------------------------- /src/cgacode/cgacode_driver.cpp: -------------------------------------------------------------------------------- 1 | #include "cgacode_driver.h" 2 | #include 3 | 4 | CC::CC_Driver::CC_Driver(ACT::ShapeTree* _shapeTree) : 5 | shapeTree(_shapeTree) 6 | {} 7 | 8 | CC::CC_Driver::~CC_Driver() { 9 | for (auto it = rules.begin() ; it != rules.end() ; it++) { 10 | delete it->second; 11 | } 12 | } 13 | 14 | string CC::CC_Driver::parseFile( const string& fileName ) { 15 | ifstream input; 16 | input.open(fileName); 17 | 18 | delete(scanner); 19 | try 20 | { 21 | scanner = new CC::CC_Scanner( &input ); 22 | } 23 | catch( std::bad_alloc &ba ) 24 | { 25 | std::cerr << "CGAcode: Failed to allocate scanner: (" << 26 | ba.what() << "), exiting!!\n"; 27 | exit( EXIT_FAILURE ); 28 | } 29 | 30 | delete(parser); 31 | try 32 | { 33 | parser = new CC::CC_Parser( (*scanner) /* scanner */, 34 | (*this) /* driver */ ); 35 | } 36 | catch( std::bad_alloc &ba ) 37 | { 38 | std::cerr << "CGAcode: Failed to allocate parser: (" << 39 | ba.what() << "), exiting!!\n"; 40 | exit( EXIT_FAILURE ); 41 | } 42 | const int accept( 0 ); 43 | if( parser->parse() != accept ) 44 | { 45 | std::cerr << "CGAcode: Parse failed !\n"; 46 | } 47 | 48 | input.close(); 49 | 50 | return initRule; 51 | } 52 | 53 | void CC::CC_Driver::initFromFile(const string& path) { 54 | shapeTree->initFromFile(path); 55 | } 56 | 57 | void CC::CC_Driver::initFromRect(double x, double y) { 58 | shapeTree->initFromRect(x,y); 59 | } 60 | 61 | void CC::CC_Driver::setOutputFilename(const string& filename) { 62 | shapeTree->setOutputFilename(filename); 63 | } 64 | 65 | void CC::CC_Driver::setTextureFile(const string& path) { 66 | shapeTree->setTextureFile(path); 67 | } 68 | 69 | void CC::CC_Driver::addTextureRect(const string& name, double x0, double y0, double x1, double y1) { 70 | shapeTree->addTextureRect(name, x0, y0, x1, y1); 71 | } 72 | 73 | void CC::CC_Driver::setRoofZoom(double zoom) { 74 | shapeTree->setRoofZoom(zoom); 75 | } 76 | 77 | void CC::CC_Driver::setRoofTexture(const string& path) { 78 | shapeTree->setRoofTexture(path); 79 | } 80 | 81 | void CC::CC_Driver::setRecDepth(const string& ruleName, double depth) { 82 | if (rules.find(ruleName) == rules.end()) 83 | std::cerr << "Error: trying to access to rule: " << ruleName 84 | << " which is not declared yet." << std::endl; 85 | 86 | else 87 | rules[ruleName]->setRecDepth(depth); 88 | } 89 | 90 | void CC::CC_Driver::setFallback(const string& ruleName, const string& fallback) { 91 | if (rules.find(ruleName) == rules.end()) 92 | std::cerr << "Error: trying to access to rule: " << ruleName 93 | << " which is not declared yet." << std::endl; 94 | 95 | else 96 | rules[ruleName]->setFallback(fallback); 97 | } 98 | 99 | void CC::CC_Driver::addRule(const string& name, double weight, const string& body) { 100 | bool isInitRule = rules.empty(); 101 | 102 | if (rules.find(name) == rules.end()) { 103 | Rule* rule = new Rule(name); 104 | rules.insert(pair(name, rule)); 105 | RuleNames::getInstance().addRule(name); 106 | shapeTree->addRule(rule); 107 | 108 | if (isInitRule) 109 | initRule = name; 110 | } 111 | 112 | rules[name]->addAction(body, weight); 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/cgacode/cgacode_driver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "cgacode_scanner.h" 6 | #include "cgacode_parser.h" 7 | #include "../shape_tree.h" 8 | #include "../rule.h" 9 | 10 | using namespace std; 11 | 12 | namespace CC{ 13 | 14 | class CC_Driver { 15 | public: 16 | CC_Driver(ACT::ShapeTree* _shapeTree); 17 | virtual ~CC_Driver(); 18 | 19 | // Returns the name of the init rule 20 | string parseFile( const string& fileName ); 21 | 22 | void initFromFile(const string& path); 23 | void initFromRect(double x, double y); 24 | void setOutputFilename(const string& filename); 25 | void setTextureFile(const string& path); 26 | void addTextureRect(const string& name, double x0, double y0, double x1, double y1); 27 | void setRoofZoom(double zoom); 28 | void setRoofTexture(const string& path); 29 | 30 | void setRecDepth(const string& ruleName, double depth); 31 | void setFallback(const string& ruleName, const string& fallback); 32 | 33 | void addRule(const string& name, double weight, const string& body); 34 | 35 | private: 36 | CC::CC_Parser *parser = nullptr; 37 | CC::CC_Scanner *scanner = nullptr; 38 | 39 | ACT::ShapeTree* shapeTree; 40 | map rules; 41 | 42 | string initRule; 43 | }; 44 | 45 | } /* End namespace CC */ 46 | -------------------------------------------------------------------------------- /src/cgacode/cgacode_scanner.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define yyFlexLexer ccFlexLexer 4 | #include 5 | #undef yyFlexLexer 6 | 7 | #include "cgacode_scanner_internal.h" 8 | -------------------------------------------------------------------------------- /src/cgacode/cgacode_scanner_internal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cgacode_parser.h" 4 | 5 | namespace CC { 6 | 7 | class CC_Scanner : public ccFlexLexer { 8 | public: 9 | CC_Scanner(std::istream *in) : ccFlexLexer(in), yylval( nullptr ){}; 10 | 11 | int yylex(CC::CC_Parser::semantic_type * const lval) { 12 | yylval = lval; 13 | return( yylex() ); 14 | } 15 | 16 | private: 17 | int yylex(); 18 | CC::CC_Parser::semantic_type *yylval; 19 | }; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/custom_join.cpp: -------------------------------------------------------------------------------- 1 | #include "custom_join.h" 2 | 3 | void CstmCGAL::join(const std::list& P, 4 | std::list& R) { 5 | 6 | CGAL::join (P.begin(), P.end(), std::back_inserter(R)); 7 | } 8 | 9 | void CstmCGAL::join(const std::list& P, 10 | const std::list& Q, 11 | std::list& R) { 12 | 13 | CGAL::join (P.begin(), P.end(), Q.begin(), Q.end(), std::back_inserter(R)); 14 | } 15 | -------------------------------------------------------------------------------- /src/custom_join.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a wrapper for the CGAL join function on polygons 3 | * This file is needed because boolean set operations conflicts with Surface_mesh 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | typedef CGAL::Simple_cartesian Kernel; 12 | typedef CGAL::Polygon_with_holes_2 Polygon_with_holes_2 ; 13 | 14 | namespace CstmCGAL { // Custom CGAL 15 | 16 | void join(const std::list& P, 17 | std::list& R); 18 | 19 | void join(const std::list& P, 20 | const std::list& Q, 21 | std::list& R); 22 | 23 | } // End of namespace Cstm CGAL 24 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "shape_tree.h" 7 | #include "cgacode/cgacode_driver.h" 8 | 9 | #include "split_pattern/split_pattern_driver.h" 10 | 11 | int main(int argv, char* argc[]) { 12 | srand(time(NULL)); 13 | 14 | if (argv != 2){ 15 | std::cout << "Usage: " << argc[0] << " " << std::endl; 16 | return 0; 17 | } 18 | 19 | std::string sourceCode = argc[1]; 20 | 21 | ACT::ShapeTree shapeTree; 22 | shapeTree.setOutputFilename(sourceCode + ".off"); 23 | 24 | // We need to complete the parsing of the code before initializing the queue 25 | // of active rules. 26 | 27 | CC::CC_Driver cgacodeDriver(&shapeTree); 28 | std::string initRule = cgacodeDriver.parseFile(sourceCode); 29 | shapeTree.setInitRule(initRule); 30 | 31 | while (shapeTree.executeRule() != -1); 32 | 33 | shapeTree.computeRoof(); 34 | 35 | shapeTree.outputGeometry(); 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /src/node.cpp: -------------------------------------------------------------------------------- 1 | #include "custom_join.h" 2 | #include "node.h" 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include "shape_tree.h" 13 | #include "split_pattern/split_pattern_driver.h" 14 | 15 | using namespace std; 16 | 17 | typedef pair Match; 18 | 19 | Node::Node(ACT::ShapeTree* _shapeTree, Node* _parent) : 20 | shapeTree(_shapeTree), 21 | parent(_parent), 22 | hasRoof(false), 23 | firstTimeSelect(true) 24 | {} 25 | 26 | void Node::selectAllFaces() { 27 | selectedFaces.clear(); 28 | 29 | Mesh::Face_range::iterator f, f_end; 30 | for (boost::tie(f,f_end) = shape.faces(); f != f_end ; f++) { 31 | selectedFaces.push_back(*f); 32 | } 33 | } 34 | 35 | void Node::noTexture() { 36 | iTexCoord.clear(); 37 | 38 | Mesh::Face_range::iterator f, f_end; 39 | for (boost::tie(f,f_end) = shape.faces(); f != f_end ; f++) { 40 | iTexCoord[*f] = 0; 41 | } 42 | } 43 | 44 | void Node::load(const string& path) { 45 | ifstream input; 46 | input.open(path); 47 | input >> shape; 48 | input.close(); 49 | selectAllFaces(); 50 | noTexture(); 51 | } 52 | 53 | void Node::setShape(Mesh _shape) { 54 | shape = _shape; 55 | selectAllFaces(); 56 | noTexture(); 57 | } 58 | 59 | void Node::addChild(Node* _child) { 60 | _child->setParent(this); 61 | children.push_back(_child); 62 | } 63 | 64 | MeshResult Node::getSubGeometry() { 65 | MeshResult res; 66 | 67 | if (hasRoof) { 68 | res.roof = roof; 69 | res.iRoofTexCoord = iRoofTexCoord; 70 | } 71 | 72 | if (children.empty()) { 73 | res.mesh = shape; 74 | res.iTexCoord = iTexCoord; 75 | 76 | return res; 77 | } 78 | 79 | else { 80 | for (auto chld = children.begin() ; chld != children.end() ; chld++) { 81 | MeshResult partialRes = (*chld)->getSubGeometry(); 82 | 83 | // Maps vertices to the appropriate texture coordinates 84 | for (auto fd = partialRes.iTexCoord.begin() ; 85 | fd != partialRes.iTexCoord.end() ; fd++) { 86 | res.iTexCoord.insert(pair( 87 | // This addition is specified in the CGAL doc 88 | (face_descriptor) (fd->first + 89 | res.mesh.number_of_faces() + 90 | res.mesh.number_of_removed_faces()), 91 | fd->second)); 92 | } 93 | 94 | res.mesh += partialRes.mesh; 95 | 96 | // Do the same for the roof 97 | for (auto fd = partialRes.iRoofTexCoord.begin() ; 98 | fd != partialRes.iRoofTexCoord.end() ; fd++) { 99 | map tmpMap; 100 | for (auto vd = fd->second.begin() ; vd != fd->second.end() ; vd++) { 101 | tmpMap.insert(pair( 102 | (vertex_descriptor) (vd->first + 103 | res.roof.number_of_vertices() + 104 | res.roof.number_of_removed_vertices()), 105 | vd->second)); 106 | } 107 | 108 | res.iRoofTexCoord.insert(pair >( 109 | (face_descriptor) (fd->first + 110 | res.roof.number_of_faces() + 111 | res.roof.number_of_removed_faces()), 112 | tmpMap)); 113 | } 114 | 115 | res.roof += partialRes.roof; 116 | } 117 | 118 | return res; 119 | } 120 | } 121 | 122 | void Node::getCeiling(vector >& result) { 123 | list save = selectedFaces; 124 | 125 | selectFace(""); selectFace("ypos"); 126 | 127 | for (auto f = selectedFaces.begin() ; f != selectedFaces.end() ; f++) { 128 | vector innerResult; 129 | CGAL::Vertex_around_face_iterator v, v_end; 130 | for(boost::tie(v, v_end) = vertices_around_face(shape.halfedge(*f), shape); 131 | v != v_end; v++){ 132 | innerResult.push_back(shape.point(*v)); 133 | } 134 | result.push_back(innerResult); 135 | } 136 | 137 | selectedFaces = save; 138 | } 139 | 140 | Node* Node::translate(Kernel::RT dx, Kernel::RT dy, Kernel::RT dz) { 141 | Mesh nShape; 142 | map idxInNewShape; 143 | CGAL::Vector_3 translation(dx,dy,dz); 144 | 145 | Mesh::Vertex_range::iterator v, v_end; 146 | for (boost::tie(v,v_end) = shape.vertices(); v != v_end ; v++) { 147 | idxInNewShape.insert(pair( 148 | *v, nShape.add_vertex(shape.point(*v) + translation))); 149 | } 150 | 151 | map nITexCoord; 152 | 153 | Mesh::Face_range::iterator f, f_end; 154 | for (boost::tie(f,f_end) = shape.faces(); f != f_end ; f++) { 155 | vector vFace; 156 | 157 | CGAL::Vertex_around_face_iterator v, v_end; 158 | for(boost::tie(v, v_end) = vertices_around_face(shape.halfedge(*f), shape); 159 | v != v_end; v++){ 160 | vFace.push_back(*v); 161 | } 162 | 163 | face_descriptor nFace; 164 | 165 | if (vFace.size() == 3) 166 | nFace = nShape.add_face(idxInNewShape[vFace[0]], 167 | idxInNewShape[vFace[1]], 168 | idxInNewShape[vFace[2]]); 169 | else // vFace.size() == 4 170 | nFace = nShape.add_face(idxInNewShape[vFace[0]], 171 | idxInNewShape[vFace[1]], 172 | idxInNewShape[vFace[2]], 173 | idxInNewShape[vFace[3]]); 174 | 175 | nITexCoord.insert(pair( nFace, iTexCoord[*f] )); 176 | } 177 | 178 | Node* tr = new Node(shapeTree, this); 179 | tr->setShape(nShape); 180 | tr->setITexCoord(nITexCoord); 181 | addChild(tr); 182 | return tr; 183 | } 184 | 185 | Node* Node::extrude(Kernel::RT height) { 186 | Mesh nShape; 187 | for (auto f = selectedFaces.begin() ; f != selectedFaces.end() ; f++) { 188 | 189 | vector iPrevShape; 190 | 191 | CGAL::Vertex_around_face_iterator v, v_end; 192 | for(boost::tie(v, v_end) = vertices_around_face(shape.halfedge(*f), shape); 193 | v != v_end; v++){ 194 | 195 | iPrevShape.push_back(*v); 196 | } 197 | 198 | CGAL::Vector_3 normal = CGAL::unit_normal(shape.point(iPrevShape[0]), 199 | shape.point(iPrevShape[1]), 200 | shape.point(iPrevShape[2])); 201 | 202 | normal = normal * height; 203 | 204 | vector iNewShape, iNewShapeExtr; 205 | 206 | for (unsigned int i = 0 ; i < iPrevShape.size() ; i++) { 207 | iNewShape.push_back(nShape.add_vertex(shape.point(iPrevShape[i]))); 208 | iNewShapeExtr.push_back(nShape.add_vertex(shape.point(iPrevShape[i]) + normal)); 209 | } 210 | 211 | face_descriptor fd; 212 | 213 | for (unsigned int i = 0 ; i < iNewShape.size() ; i++) { 214 | fd = nShape.add_face( iNewShape[i], 215 | iNewShape[(i+1) % iNewShape.size()], 216 | iNewShapeExtr[(i+1) % iNewShapeExtr.size()], 217 | iNewShapeExtr[i]); 218 | 219 | if (fd == Mesh::null_face()) 220 | cerr << "Extrude: Unable to add face" << endl; 221 | } 222 | 223 | nShape.add_face(iNewShapeExtr[0], iNewShapeExtr[1], iNewShapeExtr[2], iNewShapeExtr[3]); 224 | } 225 | 226 | Node* save = new Node(shapeTree, this); 227 | Node* extr = new Node(shapeTree, this); 228 | save->setShape(shape); 229 | save->setITexCoord(iTexCoord); 230 | extr->setShape(nShape); 231 | addChild(save); 232 | addChild(extr); 233 | return extr; 234 | } 235 | 236 | void Node::distributeX( 237 | vector >* matchVertexIn, 238 | vector* nShapes, 239 | const vector& sortedVertices, 240 | const vector& weights) { 241 | 242 | double nxtSeparator = shape.point(sortedVertices.front()).x(); // minCoord 243 | unsigned int j = 0; 244 | 245 | for (unsigned int i = 0 ; i < nShapes->size() ; i++) { 246 | nxtSeparator += weights[i]; 247 | 248 | for (; j < sortedVertices.size() && shape.point(sortedVertices[j]).x() < nxtSeparator; j++) { 249 | vertex_descriptor indexAdded = (*nShapes)[i].add_vertex(shape.point(sortedVertices[j])); 250 | (*matchVertexIn)[i].insert( Match(sortedVertices[j], indexAdded) ); 251 | 252 | CGAL::Halfedge_around_target_iterator h, h_end; 253 | for(boost::tie(h, h_end) = halfedges_around_target(sortedVertices[j], shape); 254 | h != h_end; h++){ 255 | 256 | if (shape.point(shape.source(*h)).x() > nxtSeparator) { 257 | double sep = nxtSeparator - weights[i]; 258 | unsigned int k = i; 259 | Point_3 currentPoint = shape.point(sortedVertices[j]); 260 | 261 | // Put new vertices at each border cutting the edge 262 | // We need the condition over k when the weights do not some up to maxCoord 263 | while (shape.point(shape.source(*h)).x() > sep && k < weights.size() - 1) { 264 | sep += weights[k]; 265 | 266 | Vector_3 crossingEdge(currentPoint, shape.point(shape.source(*h))); 267 | 268 | crossingEdge = crossingEdge * Kernel::RT( // Thales 269 | (sep - currentPoint.x()) / 270 | (shape.point(shape.source(*h)).x() - currentPoint.x()) ); 271 | 272 | currentPoint = currentPoint + crossingEdge; 273 | 274 | (*matchVertexIn)[k].insert( Match(shape.source(*h), (*nShapes)[k].add_vertex(currentPoint)) ); 275 | (*matchVertexIn)[k+1].insert( Match(sortedVertices[j], (*nShapes)[k+1].add_vertex(currentPoint)) ); 276 | 277 | k++; 278 | } 279 | 280 | vertex_descriptor sourceAdded = (*nShapes)[k].add_vertex(shape.point(shape.source(*h))); 281 | (*matchVertexIn)[k].insert( Match(shape.source(*h), sourceAdded) ); 282 | } 283 | } 284 | } 285 | } 286 | } 287 | 288 | void Node::distributeY( 289 | vector >* matchVertexIn, 290 | vector* nShapes, 291 | const vector& sortedVertices, 292 | const vector& weights) { 293 | 294 | double nxtSeparator = shape.point(sortedVertices.front()).y(); // minCoord 295 | unsigned int j = 0; 296 | 297 | for (unsigned int i = 0 ; i < nShapes->size() ; i++) { 298 | nxtSeparator += weights[i]; 299 | 300 | for (; j < sortedVertices.size() && shape.point(sortedVertices[j]).y() < nxtSeparator; j++) { 301 | vertex_descriptor indexAdded = (*nShapes)[i].add_vertex(shape.point(sortedVertices[j])); 302 | (*matchVertexIn)[i].insert( Match(sortedVertices[j], indexAdded) ); 303 | 304 | CGAL::Halfedge_around_target_iterator h, h_end; 305 | for(boost::tie(h, h_end) = halfedges_around_target(sortedVertices[j], shape); 306 | h != h_end; h++){ 307 | 308 | if (shape.point(shape.source(*h)).y() > nxtSeparator) { 309 | double sep = nxtSeparator - weights[i]; 310 | unsigned int k = i; 311 | Point_3 currentPoint = shape.point(sortedVertices[j]); 312 | 313 | // Put new vertices at each border cutting the edge 314 | // We need the condition over k when the weights do not some up to maxCoord 315 | while (shape.point(shape.source(*h)).y() > sep && k < weights.size() - 1) { 316 | sep += weights[k]; 317 | 318 | Vector_3 crossingEdge(currentPoint, shape.point(shape.source(*h))); 319 | 320 | crossingEdge = crossingEdge * Kernel::RT( // Thales 321 | (sep - currentPoint.y()) / 322 | (shape.point(shape.source(*h)).y() - currentPoint.y()) ); 323 | 324 | currentPoint = currentPoint + crossingEdge; 325 | 326 | (*matchVertexIn)[k].insert( Match(shape.source(*h), (*nShapes)[k].add_vertex(currentPoint)) ); 327 | (*matchVertexIn)[k+1].insert( Match(sortedVertices[j], (*nShapes)[k+1].add_vertex(currentPoint)) ); 328 | 329 | k++; 330 | } 331 | 332 | vertex_descriptor sourceAdded = (*nShapes)[k].add_vertex(shape.point(shape.source(*h))); 333 | (*matchVertexIn)[k].insert( Match(shape.source(*h), sourceAdded) ); 334 | } 335 | } 336 | } 337 | } 338 | } 339 | 340 | void Node::distributeZ( 341 | vector >* matchVertexIn, 342 | vector* nShapes, 343 | const vector& sortedVertices, 344 | const vector& weights) { 345 | 346 | double nxtSeparator = shape.point(sortedVertices.front()).z(); // minCoord 347 | unsigned int j = 0; 348 | 349 | for (unsigned int i = 0 ; i < nShapes->size() ; i++) { 350 | nxtSeparator += weights[i]; 351 | 352 | for (; j < sortedVertices.size() && shape.point(sortedVertices[j]).z() < nxtSeparator; j++) { 353 | vertex_descriptor indexAdded = (*nShapes)[i].add_vertex(shape.point(sortedVertices[j])); 354 | (*matchVertexIn)[i].insert( Match(sortedVertices[j], indexAdded) ); 355 | 356 | CGAL::Halfedge_around_target_iterator h, h_end; 357 | for(boost::tie(h, h_end) = halfedges_around_target(sortedVertices[j], shape); 358 | h != h_end; h++){ 359 | 360 | if (shape.point(shape.source(*h)).z() > nxtSeparator) { 361 | double sep = nxtSeparator - weights[i]; 362 | unsigned int k = i; 363 | Point_3 currentPoint = shape.point(sortedVertices[j]); 364 | 365 | // Put new vertices at each border cutting the edge 366 | // We need the condition over k when the weights do not some up to maxCoord 367 | while (shape.point(shape.source(*h)).z() > sep && k < weights.size() - 1) { 368 | sep += weights[k]; 369 | 370 | Vector_3 crossingEdge(currentPoint, shape.point(shape.source(*h))); 371 | 372 | crossingEdge = crossingEdge * Kernel::RT( // Thales 373 | (sep - currentPoint.z()) / 374 | (shape.point(shape.source(*h)).z() - currentPoint.z()) ); 375 | 376 | currentPoint = currentPoint + crossingEdge; 377 | 378 | (*matchVertexIn)[k].insert( Match(shape.source(*h), (*nShapes)[k].add_vertex(currentPoint)) ); 379 | (*matchVertexIn)[k+1].insert( Match(sortedVertices[j], (*nShapes)[k+1].add_vertex(currentPoint)) ); 380 | 381 | k++; 382 | } 383 | 384 | vertex_descriptor sourceAdded = (*nShapes)[k].add_vertex(shape.point(shape.source(*h))); 385 | (*matchVertexIn)[k].insert( Match(shape.source(*h), sourceAdded) ); 386 | } 387 | } 388 | } 389 | } 390 | } 391 | 392 | void Node::reconstruct( 393 | const vector >& matchVertexIn, 394 | const vector& weights, // needed to adapt the textures 395 | vector* nShapes) { 396 | 397 | for (unsigned int i = 0 ; i < nShapes->size() ; i++) { 398 | Mesh::Face_range::iterator f, f_end; 399 | for (boost::tie(f,f_end) = shape.faces(); f != f_end ; f++) { 400 | bool addFace = true; 401 | 402 | vector aroundNewFace; 403 | 404 | CGAL::Vertex_around_face_iterator v, v_end; 405 | for(boost::tie(v, v_end) = vertices_around_face(shape.halfedge(*f), shape); 406 | v != v_end; v++) { 407 | 408 | if (matchVertexIn[i].find(*v) == matchVertexIn[i].end()) { 409 | addFace = false; 410 | break; 411 | } 412 | 413 | else { 414 | aroundNewFace.push_back(matchVertexIn[i].at(*v)); 415 | } 416 | } 417 | 418 | if (addFace) { 419 | if (aroundNewFace.size() == 4) 420 | (*nShapes)[i].add_face(aroundNewFace[0], aroundNewFace[1], 421 | aroundNewFace[2], aroundNewFace[3]); 422 | 423 | else 424 | cerr << "Extrude: This face is not a quad: " << *f << endl; 425 | } 426 | } 427 | } 428 | } 429 | 430 | void Node::preserveTextures(Axis axis, const vector& nodes, 431 | const vector& weights) { 432 | selectFace(""); 433 | switch(axis) { // Textures on ends don't need to be splitted 434 | case X: 435 | selectFace("xneg"); nodes.front()->selectFace("xneg"); 436 | nodes.front()->setTexture(iTexCoord[selectedFaces.front()]); 437 | selectFace(""); nodes.front()->selectFace(""); 438 | 439 | selectFace("xpos"); nodes.back()->selectFace("xpos"); 440 | nodes.back()->setTexture(iTexCoord[selectedFaces.front()]); 441 | selectFace(""); nodes.back()->selectFace(""); 442 | 443 | selectFace("ypos"); selectFace("yneg"); selectFace("zpos"); selectFace("zneg"); 444 | break; 445 | case Y: 446 | selectFace("yneg"); nodes.front()->selectFace("yneg"); 447 | nodes.front()->setTexture(iTexCoord[selectedFaces.front()]); 448 | selectFace(""); nodes.front()->selectFace(""); 449 | 450 | selectFace("ypos"); nodes.back()->selectFace("ypos"); 451 | nodes.back()->setTexture(iTexCoord[selectedFaces.front()]); 452 | selectFace(""); nodes.back()->selectFace(""); 453 | 454 | selectFace("xpos"); selectFace("xneg"); selectFace("zpos"); selectFace("zneg"); 455 | break; 456 | case Z: 457 | selectFace("zneg"); nodes.front()->selectFace("zneg"); 458 | nodes.front()->setTexture(iTexCoord[selectedFaces.front()]); 459 | selectFace(""); nodes.front()->selectFace(""); 460 | 461 | selectFace("zpos"); nodes.back()->selectFace("zpos"); 462 | nodes.back()->setTexture(iTexCoord[selectedFaces.front()]); 463 | selectFace(""); nodes.back()->selectFace(""); 464 | 465 | selectFace("xpos"); selectFace("xneg"); selectFace("ypos"); selectFace("yneg"); 466 | break; 467 | } 468 | 469 | list save = selectedFaces; 470 | 471 | // Split textures on the sides 472 | for (auto it = selectedFaces.begin() ; it != selectedFaces.end() ; it++) { 473 | if (iTexCoord[*it] == 0) { 474 | for (unsigned int i = 0 ; i < nodes.size() ; i++) { 475 | nodes[i]->selectFace(""); 476 | nodes[i]->selectFace(getFaceString(*it)); 477 | nodes[i]->setTexture(0); 478 | nodes[i]->selectFace(""); 479 | } 480 | } 481 | 482 | else { 483 | int indexFirstNewTexture; 484 | if (axis == Y) 485 | indexFirstNewTexture = shapeTree->splitTexture(iTexCoord[*it], weights, VERTICAL); 486 | else 487 | indexFirstNewTexture = shapeTree->splitTexture(iTexCoord[*it], weights, HORIZONTAL); 488 | 489 | for (unsigned int i = 0 ; i < nodes.size() ; i++) { 490 | nodes[i]->selectFace(""); 491 | nodes[i]->selectFace(getFaceString(*it)); 492 | nodes[i]->setTexture(indexFirstNewTexture + i*4); 493 | nodes[i]->selectFace(""); 494 | } 495 | } 496 | } 497 | 498 | // Select faces of children 499 | for (unsigned int i = 0 ; i < nodes.size() ; i++) { 500 | nodes[i]->selectAllFaces(); 501 | } 502 | 503 | selectedFaces = save; 504 | } 505 | 506 | struct CompX { 507 | Mesh *shape; 508 | bool operator() (vertex_descriptor i,vertex_descriptor j) { return CGAL::compare_x(shape->point(i),shape->point(j)) == -1; } 509 | }; 510 | 511 | struct CompY { 512 | Mesh *shape; 513 | bool operator() (vertex_descriptor i,vertex_descriptor j) { return CGAL::compare_y(shape->point(i),shape->point(j)) == -1; } 514 | }; 515 | 516 | struct CompZ { 517 | Mesh *shape; 518 | bool operator() (vertex_descriptor i,vertex_descriptor j) { return CGAL::compare_z(shape->point(i),shape->point(j)) == -1; } 519 | }; 520 | 521 | void Node::split(Axis axis, vector& nodes, vector& actions, string pattern) { 522 | SP::SP_Driver driver; 523 | driver.parse(pattern.c_str()); 524 | 525 | // Sort vertices according to the axis 526 | 527 | vector vertices; 528 | 529 | Mesh::Vertex_range::iterator v, v_end; 530 | for (boost::tie(v,v_end) = shape.vertices(); v != v_end ; v++) { 531 | vertices.push_back(*v); 532 | } 533 | 534 | if (!vertices.empty()) { 535 | 536 | switch(axis) { 537 | case X: 538 | struct CompX compX; compX.shape = &shape; 539 | sort(vertices.begin(), vertices.end(), compX); 540 | driver.computePattern(shape.point(vertices.back()).x() 541 | - shape.point(vertices.front()).x()); 542 | break; 543 | case Y: 544 | struct CompY compY; compY.shape = &shape; 545 | sort(vertices.begin(), vertices.end(), compY); 546 | driver.computePattern(shape.point(vertices.back()).y() 547 | - shape.point(vertices.front()).y()); 548 | break; 549 | case Z: 550 | struct CompZ compZ; compZ.shape = &shape; 551 | sort(vertices.begin(), vertices.end(), compZ); 552 | driver.computePattern(shape.point(vertices.back()).z() 553 | - shape.point(vertices.front()).z()); 554 | break; 555 | } 556 | 557 | // Useful variables 558 | 559 | vector weights = driver.getWeights(); 560 | actions = driver.getActions(); 561 | 562 | vector > matchVertexIn; // Matches a vertex of shape to a vertex of a sub shape 563 | matchVertexIn.resize(weights.size()); 564 | 565 | vector nShapes; 566 | nShapes.resize(weights.size()); 567 | 568 | // Distribute Vertices 569 | 570 | switch(axis) { 571 | case X: 572 | distributeX(&matchVertexIn, &nShapes, vertices, weights); 573 | break; 574 | case Y: 575 | distributeY(&matchVertexIn, &nShapes, vertices, weights); 576 | break; 577 | case Z: 578 | distributeZ(&matchVertexIn, &nShapes, vertices, weights); 579 | break; 580 | } 581 | 582 | // Reconstruct faces 583 | 584 | reconstruct(matchVertexIn, weights, &nShapes); 585 | 586 | // Store results 587 | 588 | Node* subd = new Node(shapeTree, this); 589 | subd->setShape(shape); 590 | 591 | nodes.resize(weights.size()); 592 | 593 | for (unsigned int i = 0 ; i < nShapes.size() ; i++) { 594 | nodes[i] = new Node(shapeTree, subd); 595 | nodes[i]->setShape(nShapes[i]); 596 | subd->addChild(nodes[i]); 597 | } 598 | 599 | // Set right textures in subnodes 600 | preserveTextures(axis, nodes, weights); 601 | 602 | addChild(subd); 603 | } 604 | 605 | else { // Vertices.emtpy() == true 606 | nodes.clear(); 607 | actions.clear(); 608 | } 609 | } 610 | 611 | string Node::getFaceString(face_descriptor f) { 612 | CGAL::Vertex_around_face_iterator v, v_end; 613 | vector indices; 614 | for(boost::tie(v, v_end) = vertices_around_face(shape.halfedge(f), shape); 615 | v != v_end; v++) { 616 | indices.push_back(*v); 617 | } 618 | 619 | CGAL::Vector_3 normal = CGAL::unit_normal(shape.point(indices[0]), 620 | shape.point(indices[1]), 621 | shape.point(indices[2])); 622 | 623 | if (normal * CGAL::Vector_3(1,0,0) > 0) 624 | return "xpos"; 625 | else if (normal * CGAL::Vector_3(-1,0,0) > 0) 626 | return "xneg"; 627 | else if (normal * CGAL::Vector_3(0,1,0) > 0) 628 | return "ypos"; 629 | else if (normal * CGAL::Vector_3(0,-1,0) > 0) 630 | return "yneg"; 631 | else if (normal * CGAL::Vector_3(0,0,1) > 0) 632 | return "zpos"; 633 | else if (normal * CGAL::Vector_3(0,0,-1) > 0) 634 | return "zneg"; 635 | 636 | return ""; 637 | } 638 | 639 | void Node::selectFace(const string& face) { 640 | bool clear = true; 641 | 642 | Mesh::Face_range::iterator f, f_end; 643 | 644 | for (boost::tie(f,f_end) = shape.faces(); f != f_end ; f++) { 645 | if (getFaceString(*f) == face) { 646 | selectedFaces.push_back(*f); 647 | clear = false; 648 | } 649 | } 650 | 651 | if (clear) 652 | selectedFaces.clear(); 653 | } 654 | 655 | void Node::setTexture(int indexFirstCoord) { 656 | for (auto f = selectedFaces.begin() ; f != selectedFaces.end() ; f++) { 657 | iTexCoord[*f] = indexFirstCoord; 658 | } 659 | } 660 | 661 | Node* Node::removeFaces() { 662 | Mesh nShape; 663 | Mesh::Vertex_range::iterator v, v_end; 664 | for (boost::tie(v,v_end) = shape.vertices(); v != v_end ; v++) { 665 | nShape.add_vertex(shape.point(*v)); 666 | } 667 | 668 | map nITexCoord; 669 | 670 | Mesh::Face_range::iterator f, f_end; 671 | for (boost::tie(f,f_end) = shape.faces(); f != f_end ; f++) { 672 | // Copy only unselected faces 673 | bool copyFace = true; 674 | for (auto it = selectedFaces.begin() ; it != selectedFaces.end() ; it++) { 675 | if (*it == *f) 676 | copyFace = false; 677 | } 678 | 679 | if (copyFace) { 680 | vector iPrevShape; 681 | CGAL::Vertex_around_face_iterator v, v_end; 682 | 683 | for(boost::tie(v, v_end) = vertices_around_face(shape.halfedge(*f), shape); 684 | v != v_end; v++){ 685 | iPrevShape.push_back(*v); 686 | } 687 | face_descriptor nf = nShape.add_face(iPrevShape[0], iPrevShape[1], 688 | iPrevShape[2], iPrevShape[3]); 689 | nITexCoord.insert(pair(nf, iTexCoord[*f])); 690 | } 691 | } 692 | 693 | Node* rm = new Node(shapeTree, this); 694 | rm->setShape(nShape); 695 | rm->setITexCoord(nITexCoord); 696 | addChild(rm); 697 | return rm; 698 | } 699 | 700 | void Node::createRoof(double _roofAngle, double _roofOffset) { 701 | roofAngle = _roofAngle; 702 | roofOffset = _roofOffset; 703 | 704 | hasRoof = true; 705 | 706 | if (parent != NULL) 707 | parent->cancelRoof(); 708 | } 709 | 710 | void Node::cancelRoof() { 711 | hasRoof = false; 712 | if (parent != NULL) 713 | parent->cancelRoof(); 714 | } 715 | 716 | void Node::addToRoof(const vector >& ceiling) { 717 | if (hasRoof) { 718 | for (unsigned int i = 0 ; i < ceiling.size() ; i++) { 719 | Kernel::FT level = ceiling[i].front().y(); 720 | 721 | Polygon_2 newPieceOfRoof; 722 | 723 | for (int j = ceiling[i].size()-1 ; j >= 0 ; j--) { 724 | newPieceOfRoof.push_back(Point_2(ceiling[i][j].x(), ceiling[i][j].z())); 725 | } 726 | 727 | roofLevels[level].push_back(Polygon_with_holes_2(newPieceOfRoof)); 728 | 729 | // std::cout << "size " << roofLevels[level].size() << std::endl; 730 | // std::cout << "vertices " << roofLevels[level].front().outer_boundary().size() << std::endl; 731 | 732 | std::list res, treated; 733 | CstmCGAL::join (roofLevels[level], res); 734 | 735 | for (auto it = res.begin() ; it != res.end() ; it++) { 736 | std::list splitted = CstmCGAL::splitPoly(*it); 737 | if (splitted.size() > 1) 738 | treated.splice(treated.end(),splitted); 739 | else 740 | treated.push_back(*it); 741 | } 742 | 743 | roofLevels[level] = treated; 744 | 745 | auto it = roofLevels.find(level); 746 | auto prev = it; 747 | 748 | if (it != roofLevels.begin()) { 749 | do { 750 | it--; 751 | list res, treated; 752 | CstmCGAL::join (it->second, prev->second, res); 753 | 754 | for (auto it2 = res.begin() ; it2 != res.end() ; it2++) { 755 | std::list splitted = CstmCGAL::splitPoly(*it2); 756 | if (splitted.size() > 1) 757 | treated.splice(treated.end(),splitted); 758 | else 759 | treated.push_back(*it2); 760 | } 761 | 762 | it->second = treated; 763 | prev--; 764 | } while (it != roofLevels.begin()); 765 | } 766 | } 767 | } 768 | 769 | else { 770 | if (parent == NULL) 771 | std::cerr << "Error in addToRoof(): No parent with roof" << std::endl; 772 | else 773 | parent->addToRoof(ceiling); 774 | } 775 | } 776 | 777 | void Node::computeRoof() { 778 | if (hasRoof) { 779 | // We run through the loop in reverse to be able to remove useless geometry in a future version 780 | for (auto lvl = roofLevels.rbegin() ; lvl != roofLevels.rend() ; lvl++) { 781 | for (auto it = lvl->second.begin() ; it != lvl->second.end() ; it++) { 782 | 783 | PwhPtr itWithOffset; 784 | 785 | if (roofOffset > 0) 786 | itWithOffset = CstmCGAL::applyOffset(roofOffset, *it); 787 | else 788 | itWithOffset = boost::make_shared(*it); 789 | 790 | SsPtr iss = CGAL::create_interior_straight_skeleton_2(*itWithOffset); 791 | map vertices; 792 | 793 | for ( Ss::Vertex_const_iterator v = iss->vertices_begin(); v != iss->vertices_end(); v++ ) { 794 | vertices.insert(pair( 795 | v, roof.add_vertex(Point_3( v->point().x(), 796 | lvl->first + tan(roofAngle)*(v->time()-roofOffset), 797 | v->point().y())) )); 798 | 799 | if (lvl->first + tan(roofAngle)*(v->time()-roofOffset) > 100 ) { 800 | std::cout << "Failed to compute straight skeleton on polygon:" << std::endl; 801 | 802 | std::vector outerBoundary = std::vector( 803 | itWithOffset->outer_boundary().vertices_begin(), itWithOffset->outer_boundary().vertices_end()); 804 | 805 | for (unsigned int i = 0 ; i < outerBoundary.size() ; i++) { 806 | std::cout << outerBoundary[i] << std::endl; 807 | } 808 | } 809 | } 810 | 811 | for ( Ss::Face_const_iterator f = iss->faces_begin(); f != iss->faces_end(); ++f ) { 812 | vector face; 813 | Ss::Halfedge_const_handle hbegin = f->halfedge(); 814 | Ss::Halfedge_const_handle h = hbegin; 815 | Ss::Halfedge_const_handle h_contour; 816 | do { 817 | if (!h->is_bisector()) 818 | h_contour = h; 819 | face.push_back(vertices[h->vertex()]); 820 | h = h->prev(); 821 | } while (h != hbegin); 822 | 823 | face_descriptor newf = roof.add_face(boost::make_iterator_range(face.begin(), face.end())); 824 | // CstmCGAL::splitFace(roof, newf); 825 | 826 | Point_2 origin = h_contour->opposite()->vertex()->point(); 827 | Vector_2 unit_contour = Vector_2(origin, h_contour->vertex()->point()); 828 | if (unit_contour.squared_length() == 0) 829 | std::cerr << "Error in computeRoof(): HDS of straight skeleton is ill formed" << std::endl; 830 | else { 831 | unit_contour = unit_contour / sqrt(unit_contour.squared_length()); 832 | 833 | h = hbegin; 834 | do { 835 | Vector_2 OM = Vector_2(origin, h->vertex()->point()); 836 | iRoofTexCoord[newf][vertices[h->vertex()]] = shapeTree->insertRoofITex(Point_2( 837 | OM * unit_contour / shapeTree->getRoofZoom(), 838 | h->vertex()->time() / cos(roofAngle) / shapeTree->getRoofZoom())); 839 | 840 | h = h->prev(); 841 | } while (h != hbegin); 842 | } 843 | } 844 | } 845 | } 846 | } 847 | 848 | for (auto it = children.begin() ; it != children.end() ; it++) 849 | (*it)->computeRoof(); 850 | } 851 | 852 | Node::~Node() { 853 | for (auto it = children.begin() ; it != children.end() ; it++) { 854 | delete *it; 855 | } 856 | } 857 | -------------------------------------------------------------------------------- /src/node.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "utils.h" 10 | 11 | using namespace std; 12 | 13 | typedef struct MeshResult { 14 | Mesh mesh; 15 | Mesh roof; 16 | map iTexCoord; 17 | map > iRoofTexCoord; 18 | } MeshResult; 19 | 20 | enum Axis {X,Y,Z}; 21 | 22 | namespace ACT { 23 | class ShapeTree; 24 | } 25 | 26 | class Node { 27 | 28 | public: 29 | Node(ACT::ShapeTree* _shapeTree, Node* _parent); 30 | ~Node(); 31 | 32 | void selectAllFaces(); 33 | void noTexture(); 34 | void load(const string& path); 35 | void setShape(Mesh _shape); 36 | inline void setParent(Node* _parent) {parent = _parent;} 37 | void addChild(Node* _child); 38 | 39 | MeshResult getSubGeometry(); 40 | inline bool isFirstTimeSelect() const {return firstTimeSelect;} 41 | inline void selected() {firstTimeSelect = false;} 42 | 43 | Node* translate(Kernel::RT dx, Kernel::RT dy, Kernel::RT dz); 44 | Node* extrude(Kernel::RT height); // Returns the new extruded shape, child of the saved old shape 45 | void split(Axis axis, vector& nodes, vector& actions, string pattern); 46 | void selectFace(const string& face); // Only (x|y|z)(pos|neg), otherwise unselect everything 47 | void setTexture(int indexFirstCoord); 48 | void addToRoof(const vector >& ceiling); 49 | void createRoof(double _roofAngle = 20*M_PI/180, double _roofOffset = 0.3); 50 | Node* removeFaces(); 51 | 52 | void getCeiling(vector >& result); 53 | void computeRoof(); 54 | 55 | private: 56 | 57 | // Split 58 | void reconstruct( 59 | const vector >& matchVertexIn, 60 | const vector& weights, 61 | vector* nShapes); 62 | void preserveTextures(Axis axis, const vector& nodes, const vector& weights); 63 | 64 | void distributeX( 65 | vector >* matchVertexIn, 66 | vector* nShapes, 67 | const vector& vertices, 68 | const vector& weights); 69 | void distributeY( 70 | vector >* matchVertexIn, 71 | vector* nShapes, 72 | const vector& vertices, 73 | const vector& weights); 74 | void distributeZ( 75 | vector >* matchVertexIn, 76 | vector* nShapes, 77 | const vector& sortedVertices, 78 | const vector& weights); 79 | 80 | string getFaceString(face_descriptor f); 81 | 82 | ACT::ShapeTree* shapeTree; 83 | Node* parent; 84 | list children; 85 | bool hasRoof; 86 | 87 | Mesh shape; // The shape is supposed to be a cube or a square 88 | map attributes; 89 | map iTexCoord; 90 | 91 | double roofAngle; 92 | double roofOffset; 93 | map > roofLevels; 94 | Mesh roof; 95 | map > iRoofTexCoord; 96 | 97 | list selectedFaces; 98 | bool firstTimeSelect; 99 | 100 | protected: 101 | inline void setITexCoord(const map& _iTexCoord) {iTexCoord = _iTexCoord;} 102 | void cancelRoof(); // Can be only called by createRoof() 103 | }; 104 | -------------------------------------------------------------------------------- /src/rule.cpp: -------------------------------------------------------------------------------- 1 | #include "rule.h" 2 | #include 3 | #include 4 | 5 | Rule::Rule (string _name) : 6 | name(_name), 7 | fallbackMode(false), 8 | fallback(""), 9 | recDepth(-1) // infinity 10 | {} 11 | 12 | Rule::~Rule() {} 13 | 14 | void Rule::addAction(const string& action, double weight) { 15 | if (weight < 0) 16 | std::cerr << "Rule::addAction: negative weight" << std::endl; 17 | 18 | else { 19 | actions.push_back(string(action)); 20 | weights.push_back(weight); 21 | 22 | totalWeight += weight; 23 | } 24 | } 25 | 26 | void Rule::addNode(Node* node, const string& actions) { 27 | affectedNodes.push_back(node); 28 | additionalActions.insert( pair(node, actions)); 29 | } 30 | 31 | string Rule::getActions(Node* node) const { 32 | if (fallbackMode) 33 | return fallback; 34 | 35 | else { 36 | double chosenAction = rand() * totalWeight / RAND_MAX; 37 | double partialWeight = 0; 38 | int iRes = 0; 39 | for (unsigned int i = 0 ; i < weights.size() ; i++) { 40 | partialWeight += weights[i]; 41 | if (partialWeight > chosenAction) { 42 | iRes = i; 43 | break; 44 | } 45 | } 46 | 47 | if (additionalActions.find(node) == additionalActions.end()) 48 | return actions[iRes]; 49 | else 50 | return actions[iRes] + additionalActions.at(node); 51 | } 52 | } 53 | 54 | set RuleNames::rules; 55 | -------------------------------------------------------------------------------- /src/rule.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "node.h" 10 | 11 | using namespace std; 12 | 13 | class Rule { 14 | public: 15 | Rule (string _name); 16 | virtual ~Rule (); 17 | 18 | void addAction(const string& action, double weight); 19 | void addNode(Node* node, const string& actions = string()); 20 | inline const string& getName() const {return name;} 21 | inline const list& getNodes() const {return affectedNodes;} 22 | string getActions(Node* node) const; // Chose action at random according to the weights 23 | void setRecDepth(int depth) {recDepth = depth;} 24 | inline int getRecDepth() const {return recDepth;} 25 | void setFallback(const string& _fallback) {fallback = _fallback;} 26 | void setFallbackMode(bool mode) {fallbackMode = mode;} 27 | 28 | private: 29 | string name; 30 | list affectedNodes; 31 | map additionalActions; 32 | vector actions; 33 | vector weights; 34 | 35 | bool fallbackMode; 36 | string fallback; 37 | 38 | double totalWeight; 39 | int recDepth; 40 | }; 41 | 42 | // This list is to be generated and then sent to the action lexer to identify rules 43 | // This is a singleton 44 | 45 | class RuleNames { 46 | public: 47 | static RuleNames& getInstance() { 48 | static RuleNames instance; 49 | return instance; 50 | } 51 | 52 | void addRule(string rule) {rules.insert(rule);} 53 | bool isRule(char* name) const {return rules.find(string(name)) != rules.end();} 54 | 55 | private: 56 | RuleNames () {} 57 | RuleNames(RuleNames const&) = delete; 58 | void operator=(RuleNames const&) = delete; 59 | 60 | static set rules; 61 | }; 62 | -------------------------------------------------------------------------------- /src/shape_tree.cpp: -------------------------------------------------------------------------------- 1 | #include "shape_tree.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | ACT::ShapeTree::ShapeTree() : 11 | root(this, NULL), 12 | outType(OFF), 13 | filename("out.off"), 14 | texCoord(4, Point_2(0,0)), // This stands for no texture 15 | roofTexture(""), 16 | roofTexZoom(1), 17 | roofTexCoord(1, Point_2(0,0)) 18 | { 19 | root.createRoof(); 20 | } 21 | 22 | ACT::ShapeTree::~ShapeTree() { 23 | // for (auto it = rules.begin() ; it != rules.end() ; it++) 24 | // delete it->second; 25 | } 26 | 27 | void ACT::ShapeTree::initFromFile(const string& path) { 28 | root.load(path); 29 | } 30 | 31 | void ACT::ShapeTree::initFromRect(double x, double y) { 32 | Mesh axiom; 33 | vector vertices; 34 | 35 | vertices.push_back(axiom.add_vertex(Point_3(-x/2, 0, -y/2))); 36 | vertices.push_back(axiom.add_vertex(Point_3(-x/2, 0, y/2))); 37 | vertices.push_back(axiom.add_vertex(Point_3( x/2, 0, y/2))); 38 | vertices.push_back(axiom.add_vertex(Point_3( x/2, 0, -y/2))); 39 | 40 | axiom.add_face( vertices[0], 41 | vertices[1], 42 | vertices[2], 43 | vertices[3]); 44 | 45 | root.setShape(axiom); 46 | } 47 | 48 | void ACT::ShapeTree::setOutputFilename(const string& _filename) { 49 | filename = _filename; 50 | string extension = filename.substr(filename.size()-4); 51 | 52 | if (extension == ".off" || extension == ".OFF") 53 | outType = OFF; 54 | else if (extension == ".obj" || extension == ".OBJ") 55 | outType = OBJ; 56 | else { 57 | cerr << "Error in setOutputFilename: unknown extension: " << extension << endl; 58 | outType = OFF; 59 | } 60 | } 61 | 62 | void ACT::ShapeTree::setTextureFile(const string& path) { 63 | texturePath = path; 64 | } 65 | 66 | void ACT::ShapeTree::addTextureRect(const string& name, double x0, double y0, double x1, double y1) { 67 | textures[name] = texCoord.size(); 68 | 69 | addTextureCoord(x0, y0, x1, y1); 70 | } 71 | 72 | void ACT::ShapeTree::addTextureCoord(double x0, double y0, double x1, double y1) { 73 | texCoord.push_back(Point_2(x0, y0)); 74 | texCoord.push_back(Point_2(x1, y0)); 75 | texCoord.push_back(Point_2(x1, y1)); 76 | texCoord.push_back(Point_2(x0, y1)); 77 | } 78 | 79 | void ACT::ShapeTree::outputGeometry() { 80 | if (outType == OFF) 81 | outputGeometryOFF(); 82 | else 83 | outputGeometryOBJ(); 84 | } 85 | 86 | void ACT::ShapeTree::displayGeometry() { 87 | if (outType == OFF) 88 | displayGeometryOFF(); 89 | else 90 | displayGeometryOBJ(); 91 | } 92 | 93 | void ACT::ShapeTree::outputGeometryOFF() { 94 | ofstream output; 95 | output.open(filename, ios::trunc); 96 | MeshResult res = root.getSubGeometry(); 97 | res.mesh += res.roof; 98 | output << res.mesh; 99 | output.close(); 100 | } 101 | 102 | void ACT::ShapeTree::displayGeometryOFF() { 103 | outputGeometryOFF(); 104 | if (execl("./mview", "./mview", "filename", NULL) == -1) 105 | cerr << "Unable to launch viewer: " << strerror(errno) << endl; 106 | } 107 | 108 | void ACT::ShapeTree::outputGeometryOBJ() { 109 | string out(filename); 110 | out.erase(out.size()-4,4); 111 | 112 | MeshResult res = root.getSubGeometry(); 113 | 114 | ofstream objStream, mtlStream; 115 | objStream.open(out + ".obj", ios::trunc); 116 | 117 | objStream << "# CGA-_interpreter generated building" << endl; 118 | 119 | string mtlFile; 120 | size_t found = out.rfind("/"); 121 | 122 | if (found == string::npos) 123 | mtlFile = out; 124 | else 125 | mtlFile = out.substr(found + 1); 126 | 127 | objStream << "mtllib " << mtlFile << ".mtl" << endl; 128 | objStream << "o Building " << endl; 129 | 130 | map vInt; 131 | map roofVInt; 132 | Mesh::Vertex_range::iterator v, v_end; 133 | 134 | int i = 1; 135 | for (boost::tie(v,v_end) = res.mesh.vertices(); v != v_end ; v++) { 136 | objStream << 'v' << ' ' << res.mesh.point(*v).x() << ' ' << 137 | res.mesh.point(*v).y() << ' ' << 138 | res.mesh.point(*v).z() << std::endl; 139 | 140 | vInt.insert(pair(*v,i)); 141 | i++; 142 | } 143 | 144 | for (boost::tie(v,v_end) = res.roof.vertices(); v != v_end ; v++) { 145 | objStream << 'v' << ' ' << res.roof.point(*v).x() << ' ' << 146 | res.roof.point(*v).y() << ' ' << 147 | res.roof.point(*v).z() << std::endl; 148 | 149 | roofVInt.insert(pair(*v,i)); 150 | i++; 151 | } 152 | 153 | for (unsigned int j = 0 ; j < texCoord.size() ; j++) { 154 | objStream << "vt" << ' ' << texCoord[j].x() << ' ' << 155 | texCoord[j].y() << std::endl; 156 | } 157 | 158 | for (unsigned int j = 0 ; j < roofTexCoord.size() ; j++) { 159 | objStream << "vt" << ' ' << roofTexCoord[j].x() << ' ' << 160 | roofTexCoord[j].y() << std::endl; 161 | } 162 | 163 | objStream << "usemtl Texture" << endl; 164 | objStream << "s off" << endl; 165 | 166 | Mesh::Face_range::iterator f, f_end; 167 | for (boost::tie(f,f_end) = res.mesh.faces(); f != f_end ; f++) { 168 | objStream << 'f'; 169 | CGAL::Vertex_around_face_iterator v, v_end; 170 | boost::tie(v, v_end) = vertices_around_face(res.mesh.halfedge(*f), res.mesh); 171 | i = res.iTexCoord[*f]+1; 172 | do { 173 | objStream << ' ' << vInt[*v] << '/' << i; 174 | i++; 175 | } while(++v != v_end); 176 | objStream << std::endl; 177 | } 178 | 179 | objStream << "usemtl RoofTexture" << endl; 180 | objStream << "s off" << endl; 181 | 182 | for (boost::tie(f,f_end) = res.roof.faces(); f != f_end ; f++) { 183 | objStream << 'f'; 184 | CGAL::Vertex_around_face_iterator v, v_end; 185 | for (boost::tie(v, v_end) = vertices_around_face(res.roof.halfedge(*f), res.roof); 186 | v != v_end ; v++) { 187 | objStream << ' ' << roofVInt[*v] << '/' << res.iRoofTexCoord[*f][*v] + texCoord.size() + 1; 188 | } 189 | objStream << std::endl; 190 | } 191 | 192 | objStream.close(); 193 | mtlStream.open(out + ".mtl", ios::trunc); 194 | 195 | mtlStream << "newmtl Texture" << endl << "map_Kd " << texturePath << endl; 196 | if (roofTexture != "") 197 | mtlStream << "newmtl RoofTexture" << endl << "map_Kd " << roofTexture << endl; 198 | 199 | mtlStream.close(); 200 | } 201 | 202 | void ACT::ShapeTree::displayGeometryOBJ() { 203 | outputGeometryOBJ(); 204 | if (execl("/usr/bin/meshlab", "meshlab", "./out.obj", NULL) == -1) 205 | cerr << "Unable to launch meshlab: " << strerror(errno) << endl; 206 | } 207 | 208 | void ACT::ShapeTree::executeActions(const string& actions) { 209 | ACT::ACT_Parser *parser = nullptr; 210 | ACT::ACT_Scanner *scanner = nullptr; 211 | std::stringstream ss( actions ); 212 | 213 | delete(scanner); 214 | try 215 | { 216 | scanner = new ACT::ACT_Scanner( &ss ); 217 | } 218 | catch( std::bad_alloc &ba ) 219 | { 220 | std::cerr << "Actions: Failed to allocate scanner: (" << 221 | ba.what() << "), exiting!!\n"; 222 | exit( EXIT_FAILURE ); 223 | } 224 | 225 | delete(parser); 226 | try 227 | { 228 | parser = new ACT::ACT_Parser( (*scanner), (*this) ); 229 | } 230 | catch( std::bad_alloc &ba ) 231 | { 232 | std::cerr << "Actions: Failed to allocate parser: (" << 233 | ba.what() << "), exiting!!\n"; 234 | exit( EXIT_FAILURE ); 235 | } 236 | const int accept( 0 ); 237 | 238 | if( parser->parse() != accept ) 239 | { 240 | std::cerr << "Actions: Parse failed !\n"; 241 | } 242 | } 243 | 244 | void ACT::ShapeTree::addRule(Rule* rule) { 245 | rules.insert(pair(rule->getName(), rule)); 246 | } 247 | 248 | void ACT::ShapeTree::setInitRule(const string& ruleName) { 249 | affectedNode = &root; 250 | addToRule(ruleName); 251 | } 252 | 253 | void ACT::ShapeTree::addToRule(const string& ruleName, const string& actions) { 254 | bool active = false; 255 | auto it = activeRules.begin(); 256 | // If the function calls itself, we have to put the rule another time in the 257 | // queue, otherwise the recursion control would be broken 258 | for ( it++ ; it != activeRules.end() ; it++) { 259 | if ((*it)->getName() == ruleName) { 260 | (*it)->addNode(affectedNode, actions); 261 | active = true; 262 | } 263 | } 264 | 265 | if (!active) { 266 | if (rules.find(ruleName) != rules.end()) { // else don't do anything 267 | if (rules[ruleName]->getRecDepth() > 0) { 268 | activeRules.push_back(new Rule(*rules[ruleName])); 269 | activeRules.back()->addNode(affectedNode, actions); 270 | rules[ruleName]->setRecDepth(rules[ruleName]->getRecDepth() - 1); 271 | } 272 | 273 | else if (rules[ruleName]->getRecDepth() == -1) { 274 | activeRules.push_back(new Rule(*rules[ruleName])); 275 | activeRules.back()->addNode(affectedNode, actions); 276 | } 277 | 278 | else { 279 | activeRules.push_back(new Rule(*rules[ruleName])); 280 | activeRules.back()->setFallbackMode(true); 281 | activeRules.back()->addNode(affectedNode, actions); 282 | } 283 | } 284 | } 285 | } 286 | 287 | int ACT::ShapeTree::executeRule() { 288 | if (!activeRules.empty()) { 289 | for ( auto it = activeRules.front()->getNodes().begin() ; 290 | it != activeRules.front()->getNodes().end() ; it++) { 291 | affectedNode = *it; 292 | std::cout << activeRules.front()->getName() << " " << 293 | activeRules.front()->getActions(*it) << std::endl; 294 | executeActions(activeRules.front()->getActions(*it)); 295 | } 296 | 297 | delete activeRules.front(); 298 | activeRules.pop_front(); 299 | return 0; 300 | } 301 | 302 | else 303 | return -1; 304 | } 305 | 306 | void ACT::ShapeTree::split(char axis, const string& pattern, const string& actions) { 307 | vector resultNodes; 308 | vector resultActions; 309 | 310 | Node* save = affectedNode; 311 | switch(axis) { 312 | case 'x': case 'X': 313 | affectedNode->split(X, resultNodes, resultActions, pattern); 314 | break; 315 | case 'y': case 'Y': 316 | affectedNode->split(Y, resultNodes, resultActions, pattern); 317 | break; 318 | case 'z': case 'Z': 319 | affectedNode->split(Z, resultNodes, resultActions, pattern); 320 | break; 321 | } 322 | 323 | for (unsigned int i = 0 ; i < resultNodes.size() ; i++) { 324 | affectedNode = resultNodes[i]; 325 | executeActions(resultActions[i] + " " + actions); 326 | } 327 | 328 | affectedNode = save; 329 | } 330 | 331 | void ACT::ShapeTree::selectFaces(const string& expression) { 332 | if (affectedNode->isFirstTimeSelect()) { 333 | affectedNode->selectFace(""); 334 | affectedNode->selected(); 335 | } 336 | 337 | if (expression == "all") 338 | affectedNode->selectAllFaces(); 339 | else if (expression == "x") { 340 | affectedNode->selectFace("xpos"); 341 | affectedNode->selectFace("xneg"); 342 | } 343 | else if (expression == "y") { 344 | affectedNode->selectFace("ypos"); 345 | affectedNode->selectFace("yneg"); 346 | } 347 | else if (expression == "z") { 348 | affectedNode->selectFace("zpos"); 349 | affectedNode->selectFace("zneg"); 350 | } 351 | 352 | else 353 | affectedNode->selectFace(expression); 354 | } 355 | 356 | void ACT::ShapeTree::setTexture(const string& texture) { 357 | if (textures.find(texture) == textures.end()) 358 | affectedNode->noTexture(); 359 | else 360 | affectedNode->setTexture(textures[texture]); 361 | } 362 | 363 | void ACT::ShapeTree::addToRoof() { 364 | vector > ceiling; 365 | affectedNode->getCeiling(ceiling); 366 | affectedNode->addToRoof(ceiling); 367 | } 368 | 369 | void ACT::ShapeTree::createRoof(double roofAngle, double roofOffset) { 370 | affectedNode->createRoof(roofAngle*M_PI/180, roofOffset); 371 | } 372 | 373 | int ACT::ShapeTree::insertRoofITex(Point_2 point) { 374 | if (roofTexture == "") 375 | return 0; 376 | 377 | else { 378 | for (unsigned int i = 0 ; i < roofTexCoord.size() ; i++) { 379 | if (roofTexCoord[i] == point) 380 | return i; 381 | } 382 | 383 | roofTexCoord.push_back(point); 384 | 385 | return roofTexCoord.size()-1; 386 | } 387 | } 388 | 389 | // base[0] = texCoord[texID] 390 | 391 | /* base[3] --- base[2] 392 | * | | 393 | * base[0] --- base[1] */ 394 | 395 | int ACT::ShapeTree::splitTexture(int texID, const vector& weights, 396 | Orientation orientation) { 397 | TexSplitKey tsk; 398 | tsk.texID = texID; 399 | tsk.weights = weights; 400 | tsk.orientation = orientation; 401 | 402 | if (subTextureLocation.find(tsk) == subTextureLocation.end()) { 403 | int res = texCoord.size(); 404 | double x0 = texCoord[texID].x(); 405 | double x1 = texCoord[texID+1].x(); 406 | double y0 = texCoord[texID].y(); 407 | double y1 = texCoord[texID+2].y(); 408 | 409 | double totalWeight = 0; 410 | for (unsigned int i = 0 ; i < weights.size() ; i++) 411 | totalWeight += weights[i]; 412 | 413 | double ratio; 414 | 415 | switch (orientation) { 416 | case VERTICAL: 417 | ratio = (y1 - y0) / totalWeight; 418 | y1 = y0 + weights[0] * ratio; 419 | addTextureCoord(x0, y0, x1, y1); 420 | for (unsigned int i = 1 ; i < weights.size() ; i++) { 421 | y0 = y1; 422 | y1 += weights[i] * ratio; 423 | addTextureCoord(x0, y0, x1, y1); 424 | } 425 | break; 426 | case HORIZONTAL: 427 | ratio = (x1 - x0) / totalWeight; 428 | x1 = x0 + weights[0] * ratio; 429 | addTextureCoord(x0, y0, x1, y1); 430 | for (unsigned int i = 1 ; i < weights.size() ; i++) { 431 | x0 = x1; 432 | x1 += weights[i] * ratio; 433 | addTextureCoord(x0, y0, x1, y1); 434 | } 435 | break; 436 | } 437 | 438 | subTextureLocation.insert(pair(tsk, res)); 439 | return res; 440 | } 441 | 442 | else { 443 | return subTextureLocation[tsk]; 444 | } 445 | } 446 | -------------------------------------------------------------------------------- /src/shape_tree.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "rule.h" 8 | #include "node.h" 9 | #include "actions/actions_parser.h" 10 | #include "actions/actions_scanner.h" 11 | 12 | using namespace std; 13 | 14 | enum Orientation {VERTICAL, HORIZONTAL}; 15 | enum OutputType {OFF, OBJ}; 16 | 17 | // To identify the location of subtextures 18 | typedef struct TexSplitKey { 19 | int texID; 20 | vector weights; 21 | Orientation orientation; 22 | } TexSplitKey; 23 | 24 | // Lexicographic order for texture split keys 25 | struct tskComp { 26 | bool operator() (const TexSplitKey& t1, const TexSplitKey& t2) const { 27 | if (t1.texID != t2.texID) 28 | return t1.texID < t2.texID; 29 | else if (t1.orientation != t2.orientation) 30 | return t1.orientation < t2.orientation; 31 | else if (t1.weights.size() != t2.weights.size()) 32 | return t1.weights.size() < t2.weights.size(); 33 | else { 34 | for (unsigned int i = 0 ; i < t1.weights.size() ; i++) { 35 | if (t1.weights[i] != t2.weights[i]) 36 | return t1.weights[i] < t2.weights[i]; 37 | } 38 | return false; 39 | } 40 | } 41 | }; 42 | 43 | namespace ACT { // ShapeTree is the driver for actions 44 | 45 | class ShapeTree { 46 | 47 | public: 48 | ShapeTree(); 49 | ~ShapeTree(); 50 | 51 | inline Node* getRoot() {return &root;} 52 | 53 | void initFromFile(const string& path); 54 | void initFromRect(double x, double y); 55 | void setOutputFilename(const string& _filename); 56 | void setTextureFile(const string& path); 57 | // Name a sub rectangle of the texture file that will constitute a texture to be applied 58 | void addTextureRect(const string& name, double x0, double y0, double x1, double y1); 59 | 60 | void outputGeometry(); 61 | void displayGeometry(); 62 | 63 | void addRule(Rule* rule); 64 | void setInitRule(const string& rule); 65 | 66 | int executeRule(); // Returns -1 if there is no more rule to be executed 67 | 68 | // Apply actions to the affected node 69 | void addToRule(const string& rule, const string& actions = string()); 70 | inline void translate(double dx, double dy, double dz) {affectedNode = affectedNode->translate(dx,dy,dz);} 71 | inline void extrude(double value) {affectedNode = affectedNode->extrude(value);} 72 | void split(char axis, const string& pattern, const string& actions = string()); 73 | void selectFaces(const string& expression); // For the moment only [(x|y|z)(pos|neg)] | all 74 | void setTexture(const string& texture); 75 | inline void removeFaces() {affectedNode = affectedNode->removeFaces();} 76 | void addToRoof(); 77 | void createRoof(double roofAngle, double roofOffset); 78 | 79 | inline void setRoofZoom(double zoom) {roofTexZoom = zoom;} 80 | inline void setRoofTexture(const string& path) {roofTexture = path;} 81 | inline void computeRoof() {root.computeRoof();} 82 | int insertRoofITex(Point_2 point); 83 | 84 | inline double getRoofZoom() const {return roofTexZoom;} 85 | 86 | // weights.size() new textures are created, it returns the index to the 1st 87 | int splitTexture(int texID, const vector& weights, Orientation orientation); 88 | 89 | private: 90 | // Parse function 91 | void executeActions(const string& actions); 92 | void addTextureCoord(double x0, double y0, double x1, double y1); 93 | 94 | void outputGeometryOFF(); 95 | void displayGeometryOFF(); 96 | void outputGeometryOBJ(); 97 | void displayGeometryOBJ(); 98 | 99 | Node root; 100 | Node* affectedNode; // To execute actions on 101 | std::list activeRules; 102 | std::map rules; 103 | OutputType outType; 104 | string filename; 105 | 106 | string texturePath; 107 | vector texCoord; 108 | map textures; // The int specifies the first index of the texture coords 109 | 110 | string roofTexture; 111 | double roofTexZoom; // Ratio between length in (u,v) domain and (x,y,z) domain 112 | vector roofTexCoord; 113 | 114 | map subTextureLocation; 115 | }; 116 | 117 | } /* End namespace ACT */ 118 | -------------------------------------------------------------------------------- /src/split_pattern/split_pattern.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include "split_pattern_scanner_internal.h" 4 | #include "split_pattern_parser.h" 5 | 6 | typedef SP::SP_Parser::token token; 7 | 8 | #define YY_NO_UNISTD_H 9 | %} 10 | 11 | %option prefix="sp" 12 | %option outfile="split_pattern_scanner.cpp" 13 | %option debug 14 | %option noyywrap 15 | %option c++ 16 | %option nodefault 17 | %option yyclass="SP::SP_Scanner" 18 | 19 | %% 20 | 21 | [ \r\t\n]* ; 22 | [\{\}\|\*:] { return yytext[0];} 23 | \~[0-9]+\.?[0-9]* { yylval->fval = atof(&yytext[1]); return token::RELWGHT; } 24 | [0-9]+\.?[0-9]* { yylval->fval = atof(yytext); return token::ABSWGHT; } 25 | [^\{\}\|\*: \r\n\t]+([^\{\}\|\*:][^\{\}\|\*: \r\n\t]+)* { 26 | yylval->sval = strdup(yytext); return token::ACTIONS; 27 | } // We cut spaces before and after and keep the sentence 28 | %% 29 | -------------------------------------------------------------------------------- /src/split_pattern/split_pattern.y: -------------------------------------------------------------------------------- 1 | %skeleton "lalr1.cc" 2 | %require "3.0" 3 | %debug 4 | %defines "split_pattern_parser.h" 5 | %define api.namespace{SP} 6 | %define api.prefix {sp} 7 | %define parser_class_name {SP_Parser} 8 | 9 | %code requires{ 10 | namespace SP { 11 | class SP_Scanner; 12 | class SP_Driver; 13 | } 14 | } 15 | 16 | %parse-param { SP_Scanner &scanner } 17 | %parse-param { SP_Driver &driver } 18 | 19 | %code{ 20 | #include 21 | #include 22 | #include 23 | 24 | #include "split_pattern_scanner.h" 25 | #include "split_pattern_driver.h" 26 | 27 | #undef yylex 28 | #define yylex scanner.splex 29 | } 30 | 31 | %output "split_pattern_parser.cpp" 32 | 33 | %union { 34 | float fval; 35 | int ival; 36 | char* sval; 37 | } 38 | 39 | %token RELWGHT 40 | %token ABSWGHT 41 | %token ACTIONS 42 | 43 | %% 44 | %start block; 45 | block: 46 | cst_block {driver.wasConstScope();} 47 | | var_block {driver.exitSubScope();} 48 | ; 49 | 50 | cst_block: 51 | '{' { 52 | Elmt* elmt = new Elmt(); 53 | elmt->type = SCOPE; 54 | driver.addElement(elmt); 55 | driver.enterSubScope(); 56 | } 57 | body '}' 58 | ; 59 | 60 | body: 61 | part 62 | | body '|' part 63 | ; 64 | 65 | part: 66 | block 67 | | RELWGHT ':' ACTIONS { 68 | Elmt* elmt = new Elmt(); 69 | elmt->type = RELWGHT; 70 | elmt->value = $1; 71 | elmt->actions = std::string($3); 72 | driver.addElement(elmt); 73 | } 74 | 75 | | ABSWGHT ':' ACTIONS { 76 | Elmt* elmt = new Elmt(); 77 | elmt->type = ABSWGHT; 78 | elmt->value = $1; 79 | elmt->actions = std::string($3); 80 | driver.addElement(elmt); 81 | } 82 | ; 83 | 84 | var_block: 85 | cst_block '*' 86 | ; 87 | 88 | %% 89 | 90 | void SP::SP_Parser::error( const std::string &err_message ) { 91 | std::cerr << "Split pattern : error: " << err_message << std::endl; 92 | } 93 | -------------------------------------------------------------------------------- /src/split_pattern/split_pattern_driver.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "split_pattern_driver.h" 7 | 8 | SP::SP_Driver::SP_Driver() : 9 | hasRelWeight(false) { 10 | currentScope.push(&pattern); 11 | } 12 | 13 | SP::SP_Driver::~SP_Driver() { 14 | delete(scanner); 15 | scanner = nullptr; 16 | delete(parser); 17 | parser = nullptr; 18 | 19 | deleteScope(pattern); 20 | } 21 | 22 | void SP::SP_Driver::deleteScope(std::list scope) { 23 | for (auto it = scope.begin() ; it != scope.end() ; it++) { 24 | switch((*it)->type) { 25 | case RELWGHT: 26 | case ABSWGHT: 27 | delete *it; 28 | break; 29 | case SCOPE: 30 | deleteScope((*it)->subElmts); 31 | delete *it; 32 | break; 33 | } 34 | } 35 | } 36 | 37 | void SP::SP_Driver::parse( const char * const string ) { 38 | std::stringstream ss( string ); 39 | 40 | delete(scanner); 41 | try 42 | { 43 | scanner = new SP::SP_Scanner( &ss ); 44 | } 45 | catch( std::bad_alloc &ba ) 46 | { 47 | std::cerr << "Split_pattern: Failed to allocate scanner: (" << 48 | ba.what() << "), exiting!!\n"; 49 | exit( EXIT_FAILURE ); 50 | } 51 | 52 | delete(parser); 53 | try 54 | { 55 | parser = new SP::SP_Parser( (*scanner) /* scanner */, 56 | (*this) /* driver */ ); 57 | } 58 | catch( std::bad_alloc &ba ) 59 | { 60 | std::cerr << "Split_pattern: Failed to allocate parser: (" << 61 | ba.what() << "), exiting!!\n"; 62 | exit( EXIT_FAILURE ); 63 | } 64 | const int accept( 0 ); 65 | if( parser->parse() != accept ) 66 | { 67 | std::cerr << "Split_pattern: Parse failed !\n"; 68 | } 69 | } 70 | 71 | void SP::SP_Driver::addElement(Elmt* elmt) { 72 | currentScope.top()->push_back(elmt); 73 | 74 | if (currentScope.top()->back()->type == SCOPE) { 75 | currentScope.top()->back()->value = repetitions.size(); 76 | repetitions.push_back(0); 77 | } 78 | 79 | else if (currentScope.top()->back()->type == RELWGHT) 80 | hasRelWeight = true; 81 | } 82 | 83 | void SP::SP_Driver::enterSubScope() { 84 | if (currentScope.top()->back()->type == SCOPE) { 85 | currentScope.push(&(currentScope.top()->back()->subElmts)); 86 | } 87 | else 88 | std::cerr << "Error entering subscope : not a SCOPE element" << std::endl; 89 | } 90 | 91 | void SP::SP_Driver::wasConstScope() { // Append the subscope to the list 92 | std::list* subscope = currentScope.top(); 93 | currentScope.pop(); 94 | repetitions[currentScope.top()->back()->value] = -1; // Not to be repeated 95 | currentScope.top()->pop_back(); 96 | currentScope.top()->splice(currentScope.top()->end(), *subscope); 97 | } 98 | 99 | void SP::SP_Driver::computePattern(double _totalLength) { 100 | totalLength = _totalLength; 101 | 102 | 103 | if (!hasRelWeight) { 104 | /* In this case we only repeat the first star seen, all the other are 105 | * merely removed. We adapt the repetitions so that it matches the total 106 | * length 107 | */ 108 | computeAbsPattern(); 109 | } 110 | 111 | else 112 | optimizeCoordinate(repetitions.size()-1); 113 | 114 | instantiate(); 115 | computeFinalVectors(); 116 | } 117 | 118 | void SP::SP_Driver::computeAbsPattern() { 119 | double remainingLength = totalLength; 120 | double repeatedLength = 0.f; 121 | bool once = false; 122 | 123 | 124 | for (auto it = pattern.begin() ; it != pattern.end() ; it++) { 125 | if ((*it)->type == SCOPE) { 126 | if (!once) { 127 | once = true; 128 | for (auto it2 = (*it)->subElmts.begin() ; it2 != (*it)->subElmts.end() ; it2++) { 129 | if ((*it2)->type == ABSWGHT) 130 | repeatedLength += (*it2)->value; 131 | } 132 | } 133 | } 134 | 135 | else 136 | remainingLength -= (*it)->value; 137 | } 138 | 139 | 140 | if (remainingLength < 0.f) 141 | std::cerr << "Error: total length is too small for given pattern" << std::endl; 142 | 143 | else { 144 | // The little constant is to avoid rounding errors 145 | repetitions[0] = remainingLength / repeatedLength + 0.00001; // All the others values are 0 146 | } 147 | } 148 | 149 | // We only find a local minimum 150 | void SP::SP_Driver::optimizeCoordinate(int n) { // n = coord 151 | if (repetitions[n] != -1) { 152 | repetitions[n] = 1; 153 | if (n != 0) 154 | optimizeCoordinate(n-1); 155 | else 156 | instantiate(); 157 | double prevScore = DBL_MAX; 158 | double newScore = fabs((totalLength - totalAbsLength) / totalRelWeight - 1.f); 159 | 160 | std::vector prevRepetitions; 161 | 162 | while (newScore < prevScore && totalAbsLength <= totalLength) { 163 | prevRepetitions = repetitions; 164 | repetitions[n]++; 165 | if (n != 0) 166 | optimizeCoordinate(n-1); 167 | else 168 | instantiate(); 169 | prevScore = newScore; 170 | newScore = fabs((totalLength - totalAbsLength) / totalRelWeight - 1.f); 171 | } 172 | 173 | repetitions = prevRepetitions; // To match with prevScore 174 | } 175 | 176 | else if (n != 0) 177 | optimizeCoordinate(n-1); 178 | 179 | else 180 | instantiate(); 181 | } 182 | 183 | void SP::SP_Driver::computeFinalVectors() { 184 | finalWeights.clear(); 185 | finalActions.clear(); 186 | 187 | double remainingRelLength = totalLength - totalAbsLength; 188 | 189 | for (auto it = patternInstance.begin() ; it != patternInstance.end() ; it++) { 190 | finalActions.push_back((*it)->actions); 191 | 192 | if ((*it)->type == ABSWGHT) 193 | finalWeights.push_back((*it)->value); 194 | 195 | else // type = RELWGHT 196 | finalWeights.push_back((*it)->value * remainingRelLength / totalRelWeight); 197 | } 198 | } 199 | 200 | void SP::SP_Driver::instantiate() { 201 | patternInstance.clear(); 202 | totalRelWeight = 0.f; 203 | totalAbsLength = 0.f; 204 | instantiateScope(pattern); 205 | } 206 | 207 | void SP::SP_Driver::instantiateScope(std::list scope) { 208 | for (auto it = scope.begin() ; it != scope.end() ; it++) { 209 | switch((*it)->type) { 210 | case RELWGHT: 211 | totalRelWeight += (*it)->value; 212 | patternInstance.push_back(*it); 213 | break; 214 | case ABSWGHT: 215 | totalAbsLength += (*it)->value; 216 | patternInstance.push_back(*it); 217 | break; 218 | case SCOPE: 219 | for (int i = 0 ; i < repetitions[(*it)->value] ; i++) 220 | instantiateScope((*it)->subElmts); 221 | break; 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /src/split_pattern/split_pattern_driver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "split_pattern_scanner.h" 7 | #include "split_pattern_parser.h" 8 | 9 | namespace SP{ 10 | 11 | enum DataType {RELWGHT, ABSWGHT, SCOPE}; 12 | 13 | typedef struct Elmt{ 14 | SP::DataType type; 15 | double value; // Weight or # of scope if it is repeated 16 | std::string actions; 17 | std::list subElmts; 18 | } Elmt; 19 | 20 | class SP_Driver{ 21 | public: 22 | SP_Driver(); 23 | virtual ~SP_Driver(); 24 | 25 | void parse( const char *string ); 26 | 27 | void addElement(Elmt* elmt); 28 | void enterSubScope(); 29 | void exitSubScope() {currentScope.pop();} 30 | void wasConstScope(); 31 | 32 | void computePattern(double _totalLength); /* Find the optimal repetitions, 33 | * then compute final vectors. */ 34 | 35 | const std::vector& getWeights() const {return finalWeights;} 36 | const std::vector& getActions() const {return finalActions;} 37 | 38 | private: 39 | void computeAbsPattern(); 40 | void optimizeCoordinate(int n); 41 | void computeFinalVectors(); 42 | void instantiate(); 43 | void instantiateScope(std::list scope); 44 | void deleteScope(std::list scope); 45 | 46 | SP::SP_Parser *parser = nullptr; 47 | SP::SP_Scanner *scanner = nullptr; 48 | 49 | bool hasRelWeight; 50 | double totalLength; 51 | 52 | std::stack*> currentScope; 53 | std::list pattern; 54 | std::vector repetitions; // 0 0 2 : 1st and 2nd stars are ignored, 3rd is repeated twice 55 | // -1 if the scope does not have a star -> not to be repeated 56 | 57 | std::list patternInstance; 58 | double totalRelWeight; 59 | double totalAbsLength; 60 | 61 | std::vector finalWeights; 62 | std::vector finalActions; 63 | }; 64 | 65 | } /* End namespace SP */ 66 | -------------------------------------------------------------------------------- /src/split_pattern/split_pattern_scanner.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define yyFlexLexer spFlexLexer 4 | #include 5 | #undef yyFlexLexer 6 | 7 | #include "split_pattern_scanner_internal.h" 8 | -------------------------------------------------------------------------------- /src/split_pattern/split_pattern_scanner_internal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "split_pattern_parser.h" 4 | 5 | namespace SP { 6 | 7 | class SP_Scanner : public spFlexLexer { 8 | public: 9 | SP_Scanner(std::istream *in) : spFlexLexer(in), yylval( nullptr ){}; 10 | 11 | int yylex(SP::SP_Parser::semantic_type * const lval) { 12 | yylval = lval; 13 | return( yylex() ); 14 | } 15 | 16 | private: 17 | int yylex(); 18 | SP::SP_Parser::semantic_type *yylval; 19 | }; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | typedef Ss::Halfedge_iterator Halfedge_iterator; 15 | typedef Ss::Halfedge_handle Halfedge_handle; 16 | typedef Ss::Vertex_handle Vertex_handle; 17 | 18 | typedef CGAL::Straight_skeleton_builder_traits_2 SsBuilderTraits; 19 | typedef CGAL::Straight_skeleton_builder_2 SsBuilder; 20 | 21 | typedef CGAL::Polygon_offset_builder_traits_2 OffsetBuilderTraits; 22 | typedef CGAL::Polygon_offset_builder_2 OffsetBuilder; 23 | 24 | 25 | PwhPtr CstmCGAL::applyOffset(double offset, const Polygon_with_holes_2& poly) { 26 | 27 | // This code is inspired from the CGAL example Straight_skeleton_2/Low_level_API 28 | // As the offset can only produce an interior polygon, we need to produce a frame 29 | // that encloses the polygon and is big enough so that the offset of the contour 30 | // does not interfere with the one ot the polygon. See CGAL doc page for more info 31 | boost::optional margin = CGAL::compute_outer_frame_margin( 32 | poly.outer_boundary().vertices_begin(),poly.outer_boundary().vertices_end(),offset); 33 | 34 | if ( margin ) { 35 | 36 | CGAL::Bbox_2 bbox = CGAL::bbox_2(poly.outer_boundary().vertices_begin(),poly.outer_boundary().vertices_end()); 37 | 38 | double fxmin = bbox.xmin() - *margin ; 39 | double fxmax = bbox.xmax() + *margin ; 40 | double fymin = bbox.ymin() - *margin ; 41 | double fymax = bbox.ymax() + *margin ; 42 | 43 | // Create the rectangular frame 44 | Point_2 frame[4]= { Point_2(fxmin,fymin) 45 | , Point_2(fxmax,fymin) 46 | , Point_2(fxmax,fymax) 47 | , Point_2(fxmin,fymax) 48 | } ; 49 | 50 | SsBuilder ssb ; 51 | 52 | ssb.enter_contour(frame,frame+4); 53 | 54 | // We have to revert the orientation of the polygon 55 | std::vector outerBoundary = std::vector( 56 | poly.outer_boundary().vertices_begin(),poly.outer_boundary().vertices_end()); 57 | 58 | ssb.enter_contour(outerBoundary.rbegin(), outerBoundary.rend()); 59 | 60 | SsPtr ss = ssb.construct_skeleton(); 61 | 62 | if ( ss ) { 63 | std::vector offset_contours ; 64 | 65 | OffsetBuilder ob(*ss); 66 | 67 | ob.construct_offset_contours(offset, std::back_inserter(offset_contours)); 68 | 69 | // Locate the offset contour that corresponds to the frame 70 | // That must be the outmost offset contour, which in turn must be the one 71 | // with the largest unsigned area. 72 | std::vector::iterator f = offset_contours.end(); 73 | double lLargestArea = 0.0 ; 74 | for (std::vector::iterator i = offset_contours.begin(); i != offset_contours.end(); ++ i) { 75 | double lArea = CGAL_NTS abs( (*i)->area() ) ; //Take abs() as Polygon_2::area() is signed. 76 | if ( lArea > lLargestArea ) { 77 | f = i ; 78 | lLargestArea = lArea ; 79 | } 80 | } 81 | 82 | offset_contours.erase(f); 83 | 84 | // Construct result polygon 85 | 86 | std::vector newOuterBoundary = std::vector( 87 | offset_contours.front()->vertices_begin(), offset_contours.front()->vertices_end()); 88 | 89 | Polygon_with_holes_2 result = Polygon_with_holes_2(Polygon_2(newOuterBoundary.rbegin(), newOuterBoundary.rend())); 90 | 91 | // We have to handle the holes separately 92 | 93 | for (auto it = poly.holes_begin() ; it != poly.holes_end() ; it++) { 94 | std::vector hole = std::vector(it->vertices_begin(),it->vertices_end()); 95 | 96 | std::vector holeOffsets = 97 | CGAL::create_interior_skeleton_and_offset_polygons_with_holes_2(offset, 98 | Polygon_with_holes_2(Polygon_2(hole.begin(), hole.end()))); 99 | 100 | for (auto it2 = holeOffsets.begin() ; it2 != holeOffsets.end() ; it++) { 101 | std::vector revertNewHoles = std::vector( 102 | (*it2)->outer_boundary().vertices_begin(),(*it2)->outer_boundary().vertices_end()); 103 | 104 | result.add_hole(Polygon_2(revertNewHoles.rbegin(), revertNewHoles.rend())); 105 | } 106 | } 107 | 108 | return boost::make_shared(result); 109 | } 110 | } 111 | 112 | return NULL; 113 | } 114 | 115 | std::list CstmCGAL::splitPoly(const Polygon_with_holes_2& poly) { 116 | std::vector outerBoundary = std::vector( 117 | poly.outer_boundary().vertices_begin(),poly.outer_boundary().vertices_end()); 118 | 119 | std::list result; 120 | 121 | for (unsigned int i = 0 ; i < outerBoundary.size() ; i++) { 122 | for (unsigned int j = i+1 ; j < outerBoundary.size() ; j++) { 123 | if (outerBoundary[i] == outerBoundary[j]) { 124 | result.splice(result.end(), splitPoly(Polygon_with_holes_2( 125 | Polygon_2(outerBoundary.begin() + i, outerBoundary.begin() + j) 126 | ))); 127 | 128 | for (unsigned int k = i+1 ; k < outerBoundary.size() ; k++) { 129 | outerBoundary[k] = outerBoundary[k + j - i]; 130 | } 131 | 132 | outerBoundary.resize(outerBoundary.size() - j + i); 133 | break; 134 | } 135 | } 136 | } 137 | 138 | result.push_back(Polygon_with_holes_2( 139 | Polygon_2(outerBoundary.begin(), outerBoundary.end()))); 140 | 141 | return result; 142 | } 143 | 144 | void CstmCGAL::splitFace(Mesh& mesh, face_descriptor f) { 145 | if (mesh.degree(f) > 4) { 146 | halfedge_descriptor h = mesh.halfedge(f); 147 | 148 | mesh.set_face(h,Mesh::null_face()); 149 | mesh.set_face(mesh.next(h),Mesh::null_face()); 150 | 151 | mesh.add_face( 152 | mesh.source(h), 153 | mesh.source(mesh.next(h)), 154 | mesh.source(mesh.next(mesh.next(h))) 155 | ); 156 | 157 | mesh.set_face(mesh.opposite(mesh.prev(h)),f); 158 | mesh.set_halfedge(f,mesh.opposite(mesh.prev(h))); 159 | 160 | splitFace(mesh, f); 161 | } 162 | } 163 | 164 | void CstmCGAL::splitFaces(Mesh& mesh) { 165 | Mesh::Face_range::iterator f, f_end; 166 | for (boost::tie(f,f_end) = mesh.faces(); f != f_end ; f++) { 167 | splitFace(mesh,*f); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | typedef CGAL::Simple_cartesian Kernel; 8 | typedef Kernel::Point_3 Point_3; 9 | typedef Kernel::Point_2 Point_2; 10 | typedef Kernel::Vector_3 Vector_3; 11 | typedef Kernel::Vector_2 Vector_2; 12 | 13 | typedef CGAL::Surface_mesh Mesh; 14 | typedef Mesh::Vertex_index vertex_descriptor; 15 | typedef Mesh::Halfedge_index halfedge_descriptor; 16 | typedef Mesh::Face_index face_descriptor; 17 | 18 | typedef CGAL::Polygon_2 Polygon_2 ; 19 | typedef boost::shared_ptr Polygon_2Ptr ; 20 | typedef CGAL::Polygon_with_holes_2 Polygon_with_holes_2 ; 21 | typedef CGAL::Straight_skeleton_2 Ss ; 22 | typedef boost::shared_ptr SsPtr ; 23 | typedef boost::shared_ptr PwhPtr; 24 | 25 | 26 | namespace CstmCGAL { // Custom CGAL 27 | 28 | PwhPtr applyOffset(double offset, const Polygon_with_holes_2& poly); 29 | 30 | // Sometimes polygons can be the union of 2 polygons that have one vertex in common 31 | // I should have used nef_polyhedron_2 to avoid this problem, but I only took 32 | // the time to implement a simple fix. It does not handle holes. 33 | 34 | std::list splitPoly(const Polygon_with_holes_2& poly); 35 | 36 | /* These were used to reduce polygons to triangles and square, which were the 37 | only ones supported by the original OFF viewer. However, the function did not 38 | always work when the face was concave, so I decided to change the viewer instead 39 | of investing time in fixing it. 40 | */ 41 | 42 | void splitFace(Mesh& mesh, face_descriptor f); 43 | void splitFaces(Mesh& mesh); 44 | 45 | } // End of namespace CstmCGAL 46 | --------------------------------------------------------------------------------