1# ##### BEGIN GPL LICENSE BLOCK ##### 2# 3# This program is free software; you can redistribute it and/or 4# modify it under the terms of the GNU General Public License 5# as published by the Free Software Foundation; either version 2 6# of the License, or (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program; if not, write to the Free Software Foundation, 15# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16# 17# ##### END GPL LICENSE BLOCK ##### 18 19# <pep8 compliant> 20 21""" Get POV-Ray specific objects In and Out of Blender """ 22 23import bpy 24import os.path 25from bpy_extras.io_utils import ImportHelper 26from bpy_extras import object_utils 27from bpy.utils import register_class 28from math import atan, pi, degrees, sqrt, cos, sin 29from bpy.types import Operator 30 31from bpy.props import ( 32 StringProperty, 33 BoolProperty, 34 IntProperty, 35 FloatProperty, 36 FloatVectorProperty, 37 EnumProperty, 38 PointerProperty, 39 CollectionProperty, 40) 41 42from mathutils import Vector, Matrix 43 44 45# import collections 46 47 48def pov_define_mesh(mesh, verts, edges, faces, name, hide_geometry=True): 49 """Generate proxy mesh.""" 50 if mesh is None: 51 mesh = bpy.data.meshes.new(name) 52 mesh.from_pydata(verts, edges, faces) 53 mesh.update() 54 mesh.validate( 55 verbose=False 56 ) # Set it to True to see debug messages (helps ensure you generate valid geometry). 57 if hide_geometry: 58 mesh.vertices.foreach_set("hide", [True] * len(mesh.vertices)) 59 mesh.edges.foreach_set("hide", [True] * len(mesh.edges)) 60 mesh.polygons.foreach_set("hide", [True] * len(mesh.polygons)) 61 return mesh 62 63 64class POVRAY_OT_lathe_add(Operator): 65 """Add the representation of POV lathe using a screw modifier.""" 66 67 bl_idname = "pov.addlathe" 68 bl_label = "Lathe" 69 bl_options = {'REGISTER', 'UNDO'} 70 bl_description = "adds lathe" 71 72 def execute(self, context): 73 # ayers=[False]*20 74 # layers[0]=True 75 bpy.ops.curve.primitive_bezier_curve_add( 76 location=context.scene.cursor.location, 77 rotation=(0, 0, 0), 78 # layers=layers, 79 ) 80 ob = context.view_layer.objects.active 81 ob_data = ob.data 82 ob.name = ob_data.name = "PovLathe" 83 ob_data.dimensions = '2D' 84 ob_data.transform(Matrix.Rotation(-pi / 2.0, 4, 'Z')) 85 ob.pov.object_as = 'LATHE' 86 self.report({'INFO'}, "This native POV-Ray primitive") 87 ob.pov.curveshape = "lathe" 88 bpy.ops.object.modifier_add(type='SCREW') 89 mod = ob.modifiers[-1] 90 mod.axis = 'Y' 91 mod.show_render = False 92 return {'FINISHED'} 93 94 95def pov_superellipsoid_define(context, op, ob): 96 """Create the proxy mesh of a POV superellipsoid using the pov_superellipsoid_define() function.""" 97 98 if op: 99 mesh = None 100 101 u = op.se_u 102 v = op.se_v 103 n1 = op.se_n1 104 n2 = op.se_n2 105 edit = op.se_edit 106 se_param1 = n2 # op.se_param1 107 se_param2 = n1 # op.se_param2 108 109 else: 110 assert ob 111 mesh = ob.data 112 113 u = ob.pov.se_u 114 v = ob.pov.se_v 115 n1 = ob.pov.se_n1 116 n2 = ob.pov.se_n2 117 edit = ob.pov.se_edit 118 se_param1 = ob.pov.se_param1 119 se_param2 = ob.pov.se_param2 120 121 verts = [] 122 r = 1 123 124 stepSegment = 360 / v * pi / 180 125 stepRing = pi / u 126 angSegment = 0 127 angRing = -pi / 2 128 129 step = 0 130 for ring in range(0, u - 1): 131 angRing += stepRing 132 for segment in range(0, v): 133 step += 1 134 angSegment += stepSegment 135 x = r * (abs(cos(angRing)) ** n1) * (abs(cos(angSegment)) ** n2) 136 if (cos(angRing) < 0 and cos(angSegment) > 0) or ( 137 cos(angRing) > 0 and cos(angSegment) < 0 138 ): 139 x = -x 140 y = r * (abs(cos(angRing)) ** n1) * (abs(sin(angSegment)) ** n2) 141 if (cos(angRing) < 0 and sin(angSegment) > 0) or ( 142 cos(angRing) > 0 and sin(angSegment) < 0 143 ): 144 y = -y 145 z = r * (abs(sin(angRing)) ** n1) 146 if sin(angRing) < 0: 147 z = -z 148 x = round(x, 4) 149 y = round(y, 4) 150 z = round(z, 4) 151 verts.append((x, y, z)) 152 if edit == 'TRIANGLES': 153 verts.append((0, 0, 1)) 154 verts.append((0, 0, -1)) 155 156 faces = [] 157 158 for i in range(0, u - 2): 159 m = i * v 160 for p in range(0, v): 161 if p < v - 1: 162 face = (m + p, 1 + m + p, v + 1 + m + p, v + m + p) 163 if p == v - 1: 164 face = (m + p, m, v + m, v + m + p) 165 faces.append(face) 166 if edit == 'TRIANGLES': 167 indexUp = len(verts) - 2 168 indexDown = len(verts) - 1 169 indexStartDown = len(verts) - 2 - v 170 for i in range(0, v): 171 if i < v - 1: 172 face = (indexDown, i, i + 1) 173 faces.append(face) 174 if i == v - 1: 175 face = (indexDown, i, 0) 176 faces.append(face) 177 for i in range(0, v): 178 if i < v - 1: 179 face = (indexUp, i + indexStartDown, i + indexStartDown + 1) 180 faces.append(face) 181 if i == v - 1: 182 face = (indexUp, i + indexStartDown, indexStartDown) 183 faces.append(face) 184 if edit == 'NGONS': 185 face = [] 186 for i in range(0, v): 187 face.append(i) 188 faces.append(face) 189 face = [] 190 indexUp = len(verts) - 1 191 for i in range(0, v): 192 face.append(indexUp - i) 193 faces.append(face) 194 mesh = pov_define_mesh(mesh, verts, [], faces, "SuperEllipsoid") 195 196 if not ob: 197 ob = object_utils.object_data_add(context, mesh, operator=None) 198 # engine = context.scene.render.engine what for? 199 ob = context.object 200 ob.name = ob.data.name = "PovSuperellipsoid" 201 ob.pov.object_as = 'SUPERELLIPSOID' 202 ob.pov.se_param1 = n2 203 ob.pov.se_param2 = n1 204 205 ob.pov.se_u = u 206 ob.pov.se_v = v 207 ob.pov.se_n1 = n1 208 ob.pov.se_n2 = n2 209 ob.pov.se_edit = edit 210 211 bpy.ops.object.mode_set(mode="EDIT") 212 bpy.ops.mesh.hide(unselected=False) 213 bpy.ops.object.mode_set(mode="OBJECT") 214 215 216class POVRAY_OT_superellipsoid_add(Operator): 217 """Add the representation of POV superellipsoid using the pov_superellipsoid_define() function.""" 218 219 bl_idname = "pov.addsuperellipsoid" 220 bl_label = "Add SuperEllipsoid" 221 bl_description = "Create a SuperEllipsoid" 222 bl_options = {'REGISTER', 'UNDO'} 223 COMPAT_ENGINES = {'POVRAY_RENDER'} 224 225 # XXX Keep it in sync with __init__'s RenderPovSettingsConePrimitive 226 # If someone knows how to define operators' props from a func, I'd be delighted to learn it! 227 se_param1: FloatProperty( 228 name="Parameter 1", description="", min=0.00, max=10.0, default=0.04 229 ) 230 231 se_param2: FloatProperty( 232 name="Parameter 2", description="", min=0.00, max=10.0, default=0.04 233 ) 234 235 se_u: IntProperty( 236 name="U-segments", 237 description="radial segmentation", 238 default=20, 239 min=4, 240 max=265, 241 ) 242 se_v: IntProperty( 243 name="V-segments", 244 description="lateral segmentation", 245 default=20, 246 min=4, 247 max=265, 248 ) 249 se_n1: FloatProperty( 250 name="Ring manipulator", 251 description="Manipulates the shape of the Ring", 252 default=1.0, 253 min=0.01, 254 max=100.0, 255 ) 256 se_n2: FloatProperty( 257 name="Cross manipulator", 258 description="Manipulates the shape of the cross-section", 259 default=1.0, 260 min=0.01, 261 max=100.0, 262 ) 263 se_edit: EnumProperty( 264 items=[ 265 ("NOTHING", "Nothing", ""), 266 ("NGONS", "N-Gons", ""), 267 ("TRIANGLES", "Triangles", ""), 268 ], 269 name="Fill up and down", 270 description="", 271 default='TRIANGLES', 272 ) 273 274 @classmethod 275 def poll(cls, context): 276 engine = context.scene.render.engine 277 return engine in cls.COMPAT_ENGINES 278 279 def execute(self, context): 280 pov_superellipsoid_define(context, self, None) 281 282 self.report( 283 {'INFO'}, 284 "This native POV-Ray primitive won't have any vertex to show in edit mode", 285 ) 286 287 return {'FINISHED'} 288 289 290class POVRAY_OT_superellipsoid_update(Operator): 291 """Update the superellipsoid. 292 293 Delete its previous proxy geometry and rerun pov_superellipsoid_define() function 294 with the new parameters""" 295 296 bl_idname = "pov.superellipsoid_update" 297 bl_label = "Update" 298 bl_description = "Update Superellipsoid" 299 bl_options = {'REGISTER', 'UNDO'} 300 COMPAT_ENGINES = {'POVRAY_RENDER'} 301 302 @classmethod 303 def poll(cls, context): 304 engine = context.scene.render.engine 305 ob = context.object 306 return ( 307 ob 308 and ob.data 309 and ob.type == 'MESH' 310 and engine in cls.COMPAT_ENGINES 311 ) 312 313 def execute(self, context): 314 bpy.ops.object.mode_set(mode="EDIT") 315 bpy.ops.mesh.reveal() 316 bpy.ops.mesh.select_all(action='SELECT') 317 bpy.ops.mesh.delete(type='VERT') 318 bpy.ops.object.mode_set(mode="OBJECT") 319 320 pov_superellipsoid_define(context, None, context.object) 321 322 return {'FINISHED'} 323 324 325def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): 326 faces = [] 327 if not vertIdx1 or not vertIdx2: 328 return None 329 if len(vertIdx1) < 2 and len(vertIdx2) < 2: 330 return None 331 fan = False 332 if len(vertIdx1) != len(vertIdx2): 333 if len(vertIdx1) == 1 and len(vertIdx2) > 1: 334 fan = True 335 else: 336 return None 337 total = len(vertIdx2) 338 if closed: 339 if flipped: 340 face = [vertIdx1[0], vertIdx2[0], vertIdx2[total - 1]] 341 if not fan: 342 face.append(vertIdx1[total - 1]) 343 faces.append(face) 344 345 else: 346 face = [vertIdx2[0], vertIdx1[0]] 347 if not fan: 348 face.append(vertIdx1[total - 1]) 349 face.append(vertIdx2[total - 1]) 350 faces.append(face) 351 for num in range(total - 1): 352 if flipped: 353 if fan: 354 face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]] 355 else: 356 face = [ 357 vertIdx2[num], 358 vertIdx1[num], 359 vertIdx1[num + 1], 360 vertIdx2[num + 1], 361 ] 362 faces.append(face) 363 else: 364 if fan: 365 face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]] 366 else: 367 face = [ 368 vertIdx1[num], 369 vertIdx2[num], 370 vertIdx2[num + 1], 371 vertIdx1[num + 1], 372 ] 373 faces.append(face) 374 375 return faces 376 377 378def power(a, b): 379 if a < 0: 380 return -((-a) ** b) 381 return a ** b 382 383 384def supertoroid(R, r, u, v, n1, n2): 385 a = 2 * pi / u 386 b = 2 * pi / v 387 verts = [] 388 faces = [] 389 for i in range(u): 390 s = power(sin(i * a), n1) 391 c = power(cos(i * a), n1) 392 for j in range(v): 393 c2 = R + r * power(cos(j * b), n2) 394 s2 = r * power(sin(j * b), n2) 395 verts.append( 396 (c * c2, s * c2, s2) 397 ) # type as a (mathutils.Vector(c*c2,s*c2,s2))? 398 if i > 0: 399 f = createFaces( 400 range((i - 1) * v, i * v), 401 range(i * v, (i + 1) * v), 402 closed=True, 403 ) 404 faces.extend(f) 405 f = createFaces(range((u - 1) * v, u * v), range(v), closed=True) 406 faces.extend(f) 407 return verts, faces 408 409 410def pov_supertorus_define(context, op, ob): 411 if op: 412 mesh = None 413 st_R = op.st_R 414 st_r = op.st_r 415 st_u = op.st_u 416 st_v = op.st_v 417 st_n1 = op.st_n1 418 st_n2 = op.st_n2 419 st_ie = op.st_ie 420 st_edit = op.st_edit 421 422 else: 423 assert ob 424 mesh = ob.data 425 st_R = ob.pov.st_major_radius 426 st_r = ob.pov.st_minor_radius 427 st_u = ob.pov.st_u 428 st_v = ob.pov.st_v 429 st_n1 = ob.pov.st_ring 430 st_n2 = ob.pov.st_cross 431 st_ie = ob.pov.st_ie 432 st_edit = ob.pov.st_edit 433 434 if st_ie: 435 rad1 = (st_R + st_r) / 2 436 rad2 = (st_R - st_r) / 2 437 if rad2 > rad1: 438 [rad1, rad2] = [rad2, rad1] 439 else: 440 rad1 = st_R 441 rad2 = st_r 442 if rad2 > rad1: 443 rad1 = rad2 444 verts, faces = supertoroid(rad1, rad2, st_u, st_v, st_n1, st_n2) 445 mesh = pov_define_mesh(mesh, verts, [], faces, "PovSuperTorus", True) 446 if not ob: 447 ob = object_utils.object_data_add(context, mesh, operator=None) 448 ob.pov.object_as = 'SUPERTORUS' 449 ob.pov.st_major_radius = st_R 450 ob.pov.st_minor_radius = st_r 451 ob.pov.st_u = st_u 452 ob.pov.st_v = st_v 453 ob.pov.st_ring = st_n1 454 ob.pov.st_cross = st_n2 455 ob.pov.st_ie = st_ie 456 ob.pov.st_edit = st_edit 457 458 459class POVRAY_OT_supertorus_add(Operator): 460 """Add the representation of POV supertorus using the pov_supertorus_define() function.""" 461 462 bl_idname = "pov.addsupertorus" 463 bl_label = "Add Supertorus" 464 bl_description = "Create a SuperTorus" 465 bl_options = {'REGISTER', 'UNDO'} 466 COMPAT_ENGINES = {'POVRAY_RENDER'} 467 468 st_R: FloatProperty( 469 name="big radius", 470 description="The radius inside the tube", 471 default=1.0, 472 min=0.01, 473 max=100.0, 474 ) 475 st_r: FloatProperty( 476 name="small radius", 477 description="The radius of the tube", 478 default=0.3, 479 min=0.01, 480 max=100.0, 481 ) 482 st_u: IntProperty( 483 name="U-segments", 484 description="radial segmentation", 485 default=16, 486 min=3, 487 max=265, 488 ) 489 st_v: IntProperty( 490 name="V-segments", 491 description="lateral segmentation", 492 default=8, 493 min=3, 494 max=265, 495 ) 496 st_n1: FloatProperty( 497 name="Ring manipulator", 498 description="Manipulates the shape of the Ring", 499 default=1.0, 500 min=0.01, 501 max=100.0, 502 ) 503 st_n2: FloatProperty( 504 name="Cross manipulator", 505 description="Manipulates the shape of the cross-section", 506 default=1.0, 507 min=0.01, 508 max=100.0, 509 ) 510 st_ie: BoolProperty( 511 name="Use Int.+Ext. radii", 512 description="Use internal and external radii", 513 default=False, 514 ) 515 st_edit: BoolProperty( 516 name="", description="", default=False, options={'HIDDEN'} 517 ) 518 519 @classmethod 520 def poll(cls, context): 521 engine = context.scene.render.engine 522 return engine in cls.COMPAT_ENGINES 523 524 def execute(self, context): 525 pov_supertorus_define(context, self, None) 526 527 self.report( 528 {'INFO'}, 529 "This native POV-Ray primitive won't have any vertex to show in edit mode", 530 ) 531 return {'FINISHED'} 532 533 534class POVRAY_OT_supertorus_update(Operator): 535 """Update the supertorus. 536 537 Delete its previous proxy geometry and rerun pov_supetorus_define() function 538 with the new parameters""" 539 540 bl_idname = "pov.supertorus_update" 541 bl_label = "Update" 542 bl_description = "Update SuperTorus" 543 bl_options = {'REGISTER', 'UNDO'} 544 COMPAT_ENGINES = {'POVRAY_RENDER'} 545 546 @classmethod 547 def poll(cls, context): 548 engine = context.scene.render.engine 549 ob = context.object 550 return ( 551 ob 552 and ob.data 553 and ob.type == 'MESH' 554 and engine in cls.COMPAT_ENGINES 555 ) 556 557 def execute(self, context): 558 bpy.ops.object.mode_set(mode="EDIT") 559 bpy.ops.mesh.reveal() 560 bpy.ops.mesh.select_all(action='SELECT') 561 bpy.ops.mesh.delete(type='VERT') 562 bpy.ops.object.mode_set(mode="OBJECT") 563 564 pov_supertorus_define(context, None, context.object) 565 566 return {'FINISHED'} 567 568 569######################################################################################################### 570class POVRAY_OT_loft_add(Operator): 571 """Create the representation of POV loft using Blender curves.""" 572 573 bl_idname = "pov.addloft" 574 bl_label = "Add Loft Data" 575 bl_description = "Create a Curve data for Meshmaker" 576 bl_options = {'REGISTER', 'UNDO'} 577 COMPAT_ENGINES = {'POVRAY_RENDER'} 578 579 loft_n: IntProperty( 580 name="Segments", 581 description="Vertical segments", 582 default=16, 583 min=3, 584 max=720, 585 ) 586 loft_rings_bottom: IntProperty( 587 name="Bottom", description="Bottom rings", default=5, min=2, max=100 588 ) 589 loft_rings_side: IntProperty( 590 name="Side", description="Side rings", default=10, min=2, max=100 591 ) 592 loft_thick: FloatProperty( 593 name="Thickness", 594 description="Manipulates the shape of the Ring", 595 default=0.3, 596 min=0.01, 597 max=1.0, 598 ) 599 loft_r: FloatProperty( 600 name="Radius", description="Radius", default=1, min=0.01, max=10 601 ) 602 loft_height: FloatProperty( 603 name="Height", 604 description="Manipulates the shape of the Ring", 605 default=2, 606 min=0.01, 607 max=10.0, 608 ) 609 610 def execute(self, context): 611 612 props = self.properties 613 loftData = bpy.data.curves.new('Loft', type='CURVE') 614 loftData.dimensions = '3D' 615 loftData.resolution_u = 2 616 # loftData.show_normal_face = False # deprecated in 2.8 617 n = props.loft_n 618 thick = props.loft_thick 619 side = props.loft_rings_side 620 bottom = props.loft_rings_bottom 621 h = props.loft_height 622 r = props.loft_r 623 distB = r / bottom 624 r0 = 0.00001 625 z = -h / 2 626 print("New") 627 for i in range(bottom + 1): 628 coords = [] 629 angle = 0 630 for p in range(n): 631 x = r0 * cos(angle) 632 y = r0 * sin(angle) 633 coords.append((x, y, z)) 634 angle += pi * 2 / n 635 r0 += distB 636 nurbs = loftData.splines.new('NURBS') 637 nurbs.points.add(len(coords) - 1) 638 for i, coord in enumerate(coords): 639 x, y, z = coord 640 nurbs.points[i].co = (x, y, z, 1) 641 nurbs.use_cyclic_u = True 642 for i in range(side): 643 z += h / side 644 coords = [] 645 angle = 0 646 for p in range(n): 647 x = r * cos(angle) 648 y = r * sin(angle) 649 coords.append((x, y, z)) 650 angle += pi * 2 / n 651 nurbs = loftData.splines.new('NURBS') 652 nurbs.points.add(len(coords) - 1) 653 for i, coord in enumerate(coords): 654 x, y, z = coord 655 nurbs.points[i].co = (x, y, z, 1) 656 nurbs.use_cyclic_u = True 657 r -= thick 658 for i in range(side): 659 coords = [] 660 angle = 0 661 for p in range(n): 662 x = r * cos(angle) 663 y = r * sin(angle) 664 coords.append((x, y, z)) 665 angle += pi * 2 / n 666 nurbs = loftData.splines.new('NURBS') 667 nurbs.points.add(len(coords) - 1) 668 for i, coord in enumerate(coords): 669 x, y, z = coord 670 nurbs.points[i].co = (x, y, z, 1) 671 nurbs.use_cyclic_u = True 672 z -= h / side 673 z = (-h / 2) + thick 674 distB = (r - 0.00001) / bottom 675 for i in range(bottom + 1): 676 coords = [] 677 angle = 0 678 for p in range(n): 679 x = r * cos(angle) 680 y = r * sin(angle) 681 coords.append((x, y, z)) 682 angle += pi * 2 / n 683 r -= distB 684 nurbs = loftData.splines.new('NURBS') 685 nurbs.points.add(len(coords) - 1) 686 for i, coord in enumerate(coords): 687 x, y, z = coord 688 nurbs.points[i].co = (x, y, z, 1) 689 nurbs.use_cyclic_u = True 690 ob = bpy.data.objects.new('Loft_shape', loftData) 691 scn = bpy.context.scene 692 scn.collection.objects.link(ob) 693 context.view_layer.objects.active = ob 694 ob.select_set(True) 695 ob.pov.curveshape = "loft" 696 return {'FINISHED'} 697 698 699class POVRAY_OT_plane_add(Operator): 700 """Add the representation of POV infinite plane using just a very big Blender Plane. 701 702 Flag its primitive type with a specific pov.object_as attribute and lock edit mode 703 to keep proxy consistency by hiding edit geometry.""" 704 705 bl_idname = "pov.addplane" 706 bl_label = "Plane" 707 bl_description = "Add Plane" 708 bl_options = {'REGISTER', 'UNDO'} 709 710 def execute(self, context): 711 # layers = 20*[False] 712 # layers[0] = True 713 bpy.ops.mesh.primitive_plane_add(size=100000) 714 ob = context.object 715 ob.name = ob.data.name = 'PovInfinitePlane' 716 bpy.ops.object.mode_set(mode="EDIT") 717 self.report( 718 {'INFO'}, 719 "This native POV-Ray primitive " 720 "won't have any vertex to show in edit mode", 721 ) 722 bpy.ops.mesh.hide(unselected=False) 723 bpy.ops.object.mode_set(mode="OBJECT") 724 bpy.ops.object.shade_smooth() 725 ob.pov.object_as = "PLANE" 726 return {'FINISHED'} 727 728 729class POVRAY_OT_box_add(Operator): 730 """Add the representation of POV box using a simple Blender mesh cube. 731 732 Flag its primitive type with a specific pov.object_as attribute and lock edit mode 733 to keep proxy consistency by hiding edit geometry.""" 734 735 bl_idname = "pov.addbox" 736 bl_label = "Box" 737 bl_description = "Add Box" 738 bl_options = {'REGISTER', 'UNDO'} 739 740 def execute(self, context): 741 # layers = 20*[False] 742 # layers[0] = True 743 bpy.ops.mesh.primitive_cube_add() 744 ob = context.object 745 ob.name = ob.data.name = 'PovBox' 746 bpy.ops.object.mode_set(mode="EDIT") 747 self.report( 748 {'INFO'}, 749 "This native POV-Ray primitive " 750 "won't have any vertex to show in edit mode", 751 ) 752 bpy.ops.mesh.hide(unselected=False) 753 bpy.ops.object.mode_set(mode="OBJECT") 754 ob.pov.object_as = "BOX" 755 return {'FINISHED'} 756 757 758def pov_cylinder_define(context, op, ob, radius, loc, loc_cap): 759 if op: 760 R = op.R 761 loc = bpy.context.scene.cursor.location 762 loc_cap[0] = loc[0] 763 loc_cap[1] = loc[1] 764 loc_cap[2] = loc[2] + 2 765 vec = Vector(loc_cap) - Vector(loc) 766 depth = vec.length 767 rot = Vector((0, 0, 1)).rotation_difference(vec) # Rotation from Z axis. 768 trans = rot @ Vector( 769 (0, 0, depth / 2) 770 ) # Such that origin is at center of the base of the cylinder. 771 roteuler = rot.to_euler() 772 if not ob: 773 bpy.ops.object.add(type='MESH', location=loc) 774 ob = context.object 775 ob.name = ob.data.name = "PovCylinder" 776 ob.pov.cylinder_radius = radius 777 ob.pov.cylinder_location_cap = vec 778 ob.pov.object_as = "CYLINDER" 779 else: 780 ob.location = loc 781 782 bpy.ops.object.mode_set(mode="EDIT") 783 bpy.ops.mesh.reveal() 784 bpy.ops.mesh.select_all(action='SELECT') 785 bpy.ops.mesh.delete(type='VERT') 786 bpy.ops.mesh.primitive_cylinder_add( 787 radius=radius, 788 depth=depth, 789 location=loc, 790 rotation=roteuler, 791 end_fill_type='NGON', 792 ) #'NOTHING' 793 bpy.ops.transform.translate(value=trans) 794 795 bpy.ops.mesh.hide(unselected=False) 796 bpy.ops.object.mode_set(mode="OBJECT") 797 bpy.ops.object.shade_smooth() 798 799 800class POVRAY_OT_cylinder_add(Operator): 801 """Add the representation of POV cylinder using pov_cylinder_define() function. 802 803 Use imported_cyl_loc when this operator is run by POV importer.""" 804 805 bl_idname = "pov.addcylinder" 806 bl_label = "Cylinder" 807 bl_description = "Add Cylinder" 808 bl_options = {'REGISTER', 'UNDO'} 809 810 # XXX Keep it in sync with __init__'s cylinder Primitive 811 R: FloatProperty(name="Cylinder radius", min=0.00, max=10.0, default=1.0) 812 813 imported_cyl_loc: FloatVectorProperty( 814 name="Imported Pov base location", precision=6, default=(0.0, 0.0, 0.0) 815 ) 816 817 imported_cyl_loc_cap: FloatVectorProperty( 818 name="Imported Pov cap location", precision=6, default=(0.0, 0.0, 2.0) 819 ) 820 821 def execute(self, context): 822 props = self.properties 823 R = props.R 824 ob = context.object 825 # layers = 20*[False] 826 # layers[0] = True 827 if ob: 828 if ob.pov.imported_cyl_loc: 829 LOC = ob.pov.imported_cyl_loc 830 if ob.pov.imported_cyl_loc_cap: 831 LOC_CAP = ob.pov.imported_cyl_loc_cap 832 else: 833 if not props.imported_cyl_loc: 834 LOC_CAP = LOC = bpy.context.scene.cursor.location 835 LOC_CAP[2] += 2.0 836 else: 837 LOC = props.imported_cyl_loc 838 LOC_CAP = props.imported_cyl_loc_cap 839 self.report( 840 {'INFO'}, 841 "This native POV-Ray primitive " 842 "won't have any vertex to show in edit mode", 843 ) 844 845 pov_cylinder_define(context, self, None, self.R, LOC, LOC_CAP) 846 847 return {'FINISHED'} 848 849 850class POVRAY_OT_cylinder_update(Operator): 851 """Update the POV cylinder. 852 853 Delete its previous proxy geometry and rerun pov_cylinder_define() function 854 with the new parameters""" 855 856 bl_idname = "pov.cylinder_update" 857 bl_label = "Update" 858 bl_description = "Update Cylinder" 859 bl_options = {'REGISTER', 'UNDO'} 860 COMPAT_ENGINES = {'POVRAY_RENDER'} 861 862 @classmethod 863 def poll(cls, context): 864 engine = context.scene.render.engine 865 ob = context.object 866 return ( 867 ob 868 and ob.data 869 and ob.type == 'MESH' 870 and ob.pov.object_as == "CYLINDER" 871 and engine in cls.COMPAT_ENGINES 872 ) 873 874 def execute(self, context): 875 ob = context.object 876 radius = ob.pov.cylinder_radius 877 loc = ob.location 878 loc_cap = loc + ob.pov.cylinder_location_cap 879 880 pov_cylinder_define(context, None, ob, radius, loc, loc_cap) 881 882 return {'FINISHED'} 883 884 885################################SPHERE########################################## 886def pov_sphere_define(context, op, ob, loc): 887 """create the representation of POV sphere using a Blender icosphere. 888 889 Its nice platonic solid curvature better represents pov rendertime 890 tesselation than a UV sphere""" 891 892 if op: 893 R = op.R 894 loc = bpy.context.scene.cursor.location 895 else: 896 assert ob 897 R = ob.pov.sphere_radius 898 899 # keep object rotation and location for the add object operator 900 obrot = ob.rotation_euler 901 # obloc = ob.location 902 obscale = ob.scale 903 904 bpy.ops.object.mode_set(mode="EDIT") 905 bpy.ops.mesh.reveal() 906 bpy.ops.mesh.select_all(action='SELECT') 907 bpy.ops.mesh.delete(type='VERT') 908 bpy.ops.mesh.primitive_ico_sphere_add( 909 subdivisions=4, 910 radius=ob.pov.sphere_radius, 911 location=loc, 912 rotation=obrot, 913 ) 914 # bpy.ops.transform.rotate(axis=obrot,orient_type='GLOBAL') 915 bpy.ops.transform.resize(value=obscale) 916 # bpy.ops.transform.rotate(axis=obrot, proportional_size=1) 917 918 bpy.ops.mesh.hide(unselected=False) 919 bpy.ops.object.mode_set(mode="OBJECT") 920 bpy.ops.object.shade_smooth() 921 # bpy.ops.transform.rotate(axis=obrot,orient_type='GLOBAL') 922 923 if not ob: 924 bpy.ops.mesh.primitive_ico_sphere_add( 925 subdivisions=4, radius=R, location=loc 926 ) 927 ob = context.object 928 ob.name = ob.data.name = "PovSphere" 929 ob.pov.object_as = "SPHERE" 930 ob.pov.sphere_radius = R 931 bpy.ops.object.mode_set(mode="EDIT") 932 bpy.ops.mesh.hide(unselected=False) 933 bpy.ops.object.mode_set(mode="OBJECT") 934 935 936class POVRAY_OT_sphere_add(Operator): 937 """Add the representation of POV sphere using pov_sphere_define() function. 938 939 Use imported_loc when this operator is run by POV importer.""" 940 941 bl_idname = "pov.addsphere" 942 bl_label = "Sphere" 943 bl_description = "Add Sphere Shape" 944 bl_options = {'REGISTER', 'UNDO'} 945 946 # XXX Keep it in sync with __init__'s torus Primitive 947 R: FloatProperty(name="Sphere radius", min=0.00, max=10.0, default=0.5) 948 949 imported_loc: FloatVectorProperty( 950 name="Imported Pov location", precision=6, default=(0.0, 0.0, 0.0) 951 ) 952 953 def execute(self, context): 954 props = self.properties 955 R = props.R 956 ob = context.object 957 958 if ob: 959 if ob.pov.imported_loc: 960 LOC = ob.pov.imported_loc 961 else: 962 if not props.imported_loc: 963 LOC = bpy.context.scene.cursor.location 964 965 else: 966 LOC = props.imported_loc 967 self.report( 968 {'INFO'}, 969 "This native POV-Ray primitive " 970 "won't have any vertex to show in edit mode", 971 ) 972 pov_sphere_define(context, self, None, LOC) 973 974 return {'FINISHED'} 975 976 # def execute(self,context): 977 ## layers = 20*[False] 978 ## layers[0] = True 979 980 # bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4, radius=ob.pov.sphere_radius) 981 # ob = context.object 982 # bpy.ops.object.mode_set(mode="EDIT") 983 # self.report({'INFO'}, "This native POV-Ray primitive " 984 # "won't have any vertex to show in edit mode") 985 # bpy.ops.mesh.hide(unselected=False) 986 # bpy.ops.object.mode_set(mode="OBJECT") 987 # bpy.ops.object.shade_smooth() 988 # ob.pov.object_as = "SPHERE" 989 # ob.name = ob.data.name = 'PovSphere' 990 # return {'FINISHED'} 991 992 993class POVRAY_OT_sphere_update(Operator): 994 """Update the POV sphere. 995 996 Delete its previous proxy geometry and rerun pov_sphere_define() function 997 with the new parameters""" 998 999 bl_idname = "pov.sphere_update" 1000 bl_label = "Update" 1001 bl_description = "Update Sphere" 1002 bl_options = {'REGISTER', 'UNDO'} 1003 COMPAT_ENGINES = {'POVRAY_RENDER'} 1004 1005 @classmethod 1006 def poll(cls, context): 1007 engine = context.scene.render.engine 1008 ob = context.object 1009 return ( 1010 ob 1011 and ob.data 1012 and ob.type == 'MESH' 1013 and engine in cls.COMPAT_ENGINES 1014 ) 1015 1016 def execute(self, context): 1017 1018 pov_sphere_define( 1019 context, None, context.object, context.object.location 1020 ) 1021 1022 return {'FINISHED'} 1023 1024 1025####################################CONE####################################### 1026def pov_cone_define(context, op, ob): 1027 """Add the representation of POV cone using pov_define_mesh() function. 1028 1029 Blender cone does not offer the same features such as a second radius.""" 1030 verts = [] 1031 faces = [] 1032 if op: 1033 mesh = None 1034 base = op.base 1035 cap = op.cap 1036 seg = op.seg 1037 height = op.height 1038 else: 1039 assert ob 1040 mesh = ob.data 1041 base = ob.pov.cone_base_radius 1042 cap = ob.pov.cone_cap_radius 1043 seg = ob.pov.cone_segments 1044 height = ob.pov.cone_height 1045 1046 zc = height / 2 1047 zb = -zc 1048 angle = 2 * pi / seg 1049 t = 0 1050 for i in range(seg): 1051 xb = base * cos(t) 1052 yb = base * sin(t) 1053 xc = cap * cos(t) 1054 yc = cap * sin(t) 1055 verts.append((xb, yb, zb)) 1056 verts.append((xc, yc, zc)) 1057 t += angle 1058 for i in range(seg): 1059 f = i * 2 1060 if i == seg - 1: 1061 faces.append([0, 1, f + 1, f]) 1062 else: 1063 faces.append([f + 2, f + 3, f + 1, f]) 1064 if base != 0: 1065 base_face = [] 1066 for i in range(seg - 1, -1, -1): 1067 p = i * 2 1068 base_face.append(p) 1069 faces.append(base_face) 1070 if cap != 0: 1071 cap_face = [] 1072 for i in range(seg): 1073 p = i * 2 + 1 1074 cap_face.append(p) 1075 faces.append(cap_face) 1076 1077 mesh = pov_define_mesh(mesh, verts, [], faces, "PovCone", True) 1078 if not ob: 1079 ob = object_utils.object_data_add(context, mesh, operator=None) 1080 ob.pov.object_as = "CONE" 1081 ob.pov.cone_base_radius = base 1082 ob.pov.cone_cap_radius = cap 1083 ob.pov.cone_height = height 1084 ob.pov.cone_base_z = zb 1085 ob.pov.cone_cap_z = zc 1086 1087 1088class POVRAY_OT_cone_add(Operator): 1089 """Add the representation of POV cone using pov_cone_define() function.""" 1090 1091 bl_idname = "pov.cone_add" 1092 bl_label = "Cone" 1093 bl_description = "Add Cone" 1094 bl_options = {'REGISTER', 'UNDO'} 1095 COMPAT_ENGINES = {'POVRAY_RENDER'} 1096 1097 # XXX Keep it in sync with __init__.py's RenderPovSettingsConePrimitive 1098 # If someone knows how to define operators' props from a func, I'd be delighted to learn it! 1099 base: FloatProperty( 1100 name="Base radius", 1101 description="The first radius of the cone", 1102 default=1.0, 1103 min=0.01, 1104 max=100.0, 1105 ) 1106 cap: FloatProperty( 1107 name="Cap radius", 1108 description="The second radius of the cone", 1109 default=0.3, 1110 min=0.0, 1111 max=100.0, 1112 ) 1113 seg: IntProperty( 1114 name="Segments", 1115 description="Radial segmentation of the proxy mesh", 1116 default=16, 1117 min=3, 1118 max=265, 1119 ) 1120 height: FloatProperty( 1121 name="Height", 1122 description="Height of the cone", 1123 default=2.0, 1124 min=0.01, 1125 max=100.0, 1126 ) 1127 1128 @classmethod 1129 def poll(cls, context): 1130 engine = context.scene.render.engine 1131 return engine in cls.COMPAT_ENGINES 1132 1133 def execute(self, context): 1134 pov_cone_define(context, self, None) 1135 1136 self.report( 1137 {'INFO'}, 1138 "This native POV-Ray primitive won't have any vertex to show in edit mode", 1139 ) 1140 return {'FINISHED'} 1141 1142 1143class POVRAY_OT_cone_update(Operator): 1144 """Update the POV cone. 1145 1146 Delete its previous proxy geometry and rerun pov_cone_define() function 1147 with the new parameters""" 1148 1149 bl_idname = "pov.cone_update" 1150 bl_label = "Update" 1151 bl_description = "Update Cone" 1152 bl_options = {'REGISTER', 'UNDO'} 1153 COMPAT_ENGINES = {'POVRAY_RENDER'} 1154 1155 @classmethod 1156 def poll(cls, context): 1157 engine = context.scene.render.engine 1158 ob = context.object 1159 return ( 1160 ob 1161 and ob.data 1162 and ob.type == 'MESH' 1163 and engine in cls.COMPAT_ENGINES 1164 ) 1165 1166 def execute(self, context): 1167 bpy.ops.object.mode_set(mode="EDIT") 1168 bpy.ops.mesh.reveal() 1169 bpy.ops.mesh.select_all(action='SELECT') 1170 bpy.ops.mesh.delete(type='VERT') 1171 bpy.ops.object.mode_set(mode="OBJECT") 1172 1173 pov_cone_define(context, None, context.object) 1174 1175 return {'FINISHED'} 1176 1177 1178########################################ISOSURFACES################################## 1179 1180 1181class POVRAY_OT_isosurface_box_add(Operator): 1182 """Add the representation of POV isosurface box using also just a Blender mesh cube. 1183 1184 Flag its primitive type with a specific pov.object_as attribute and lock edit mode 1185 to keep proxy consistency by hiding edit geometry.""" 1186 1187 bl_idname = "pov.addisosurfacebox" 1188 bl_label = "Isosurface Box" 1189 bl_description = "Add Isosurface contained by Box" 1190 bl_options = {'REGISTER', 'UNDO'} 1191 1192 def execute(self, context): 1193 # layers = 20*[False] 1194 # layers[0] = True 1195 bpy.ops.mesh.primitive_cube_add() 1196 ob = context.object 1197 bpy.ops.object.mode_set(mode="EDIT") 1198 self.report( 1199 {'INFO'}, 1200 "This native POV-Ray primitive " 1201 "won't have any vertex to show in edit mode", 1202 ) 1203 bpy.ops.mesh.hide(unselected=False) 1204 bpy.ops.object.mode_set(mode="OBJECT") 1205 ob.pov.object_as = "ISOSURFACE" 1206 ob.pov.contained_by = 'box' 1207 ob.name = 'PovIsosurfaceBox' 1208 return {'FINISHED'} 1209 1210 1211class POVRAY_OT_isosurface_sphere_add(Operator): 1212 """Add the representation of POV isosurface sphere by a Blender mesh icosphere. 1213 1214 Flag its primitive type with a specific pov.object_as attribute and lock edit mode 1215 to keep proxy consistency by hiding edit geometry.""" 1216 1217 bl_idname = "pov.addisosurfacesphere" 1218 bl_label = "Isosurface Sphere" 1219 bl_description = "Add Isosurface contained by Sphere" 1220 bl_options = {'REGISTER', 'UNDO'} 1221 1222 def execute(self, context): 1223 # layers = 20*[False] 1224 # layers[0] = True 1225 bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4) 1226 ob = context.object 1227 bpy.ops.object.mode_set(mode="EDIT") 1228 self.report( 1229 {'INFO'}, 1230 "This native POV-Ray primitive " 1231 "won't have any vertex to show in edit mode", 1232 ) 1233 bpy.ops.mesh.hide(unselected=False) 1234 bpy.ops.object.mode_set(mode="OBJECT") 1235 bpy.ops.object.shade_smooth() 1236 ob.pov.object_as = "ISOSURFACE" 1237 ob.pov.contained_by = 'sphere' 1238 ob.name = 'PovIsosurfaceSphere' 1239 return {'FINISHED'} 1240 1241 1242class POVRAY_OT_sphere_sweep_add(Operator): 1243 """Add the representation of POV sphere_sweep using a Blender NURBS curve. 1244 1245 Flag its primitive type with a specific ob.pov.curveshape attribute and 1246 leave access to edit mode to keep user editable handles.""" 1247 1248 bl_idname = "pov.addspheresweep" 1249 bl_label = "Sphere Sweep" 1250 bl_description = "Create Sphere Sweep along curve" 1251 bl_options = {'REGISTER', 'UNDO'} 1252 1253 def execute(self, context): 1254 # layers = 20*[False] 1255 # layers[0] = True 1256 bpy.ops.curve.primitive_nurbs_curve_add() 1257 ob = context.object 1258 ob.name = ob.data.name = "PovSphereSweep" 1259 ob.pov.curveshape = "sphere_sweep" 1260 ob.data.bevel_depth = 0.02 1261 ob.data.bevel_resolution = 4 1262 ob.data.fill_mode = 'FULL' 1263 # ob.data.splines[0].order_u = 4 1264 1265 return {'FINISHED'} 1266 1267 1268class POVRAY_OT_blob_add(Operator): 1269 """Add the representation of POV blob using a Blender meta ball. 1270 1271 No need to flag its primitive type as meta are exported to blobs 1272 and leave access to edit mode to keep user editable thresholds.""" 1273 1274 bl_idname = "pov.addblobsphere" 1275 bl_label = "Blob Sphere" 1276 bl_description = "Add Blob Sphere" 1277 bl_options = {'REGISTER', 'UNDO'} 1278 1279 def execute(self, context): 1280 # layers = 20*[False] 1281 # layers[0] = True 1282 bpy.ops.object.metaball_add(type='BALL') 1283 ob = context.object 1284 ob.name = "PovBlob" 1285 return {'FINISHED'} 1286 1287 1288class POVRAY_OT_rainbow_add(Operator): 1289 """Add the representation of POV rainbow using a Blender spot light. 1290 1291 Rainbows indeed propagate along a visibility cone. 1292 Flag its primitive type with a specific ob.pov.object_as attribute 1293 and leave access to edit mode to keep user editable handles. 1294 Add a constraint to orient it towards camera because POV Rainbows 1295 are view dependant and having it always initially visible is less 1296 confusing """ 1297 1298 bl_idname = "pov.addrainbow" 1299 bl_label = "Rainbow" 1300 bl_description = "Add Rainbow" 1301 bl_options = {'REGISTER', 'UNDO'} 1302 1303 def execute(self, context): 1304 cam = context.scene.camera 1305 bpy.ops.object.light_add(type='SPOT', radius=1) 1306 ob = context.object 1307 ob.data.show_cone = False 1308 ob.data.spot_blend = 0.5 1309 # ob.data.shadow_buffer_clip_end = 0 # deprecated in 2.8 1310 ob.data.shadow_buffer_clip_start = 4 * cam.location.length 1311 ob.data.distance = cam.location.length 1312 ob.data.energy = 0 1313 ob.name = ob.data.name = "PovRainbow" 1314 ob.pov.object_as = "RAINBOW" 1315 1316 # obj = context.object 1317 bpy.ops.object.constraint_add(type='DAMPED_TRACK') 1318 1319 ob.constraints["Damped Track"].target = cam 1320 ob.constraints["Damped Track"].track_axis = 'TRACK_NEGATIVE_Z' 1321 ob.location = -cam.location 1322 1323 # refocus on the actual rainbow 1324 bpy.context.view_layer.objects.active = ob 1325 ob.select_set(True) 1326 1327 return {'FINISHED'} 1328 1329 1330class POVRAY_OT_height_field_add(bpy.types.Operator, ImportHelper): 1331 """Add the representation of POV height_field using a displaced grid. 1332 1333 texture slot fix and displace modifier will be needed because noise 1334 displace operator was deprecated in 2.8""" 1335 1336 bl_idname = "pov.addheightfield" 1337 bl_label = "Height Field" 1338 bl_description = "Add Height Field" 1339 bl_options = {'REGISTER', 'UNDO'} 1340 1341 # XXX Keep it in sync with __init__'s hf Primitive 1342 # filename_ext = ".png" 1343 1344 # filter_glob = StringProperty( 1345 # default="*.exr;*.gif;*.hdr;*.iff;*.jpeg;*.jpg;*.pgm;*.png;*.pot;*.ppm;*.sys;*.tga;*.tiff;*.EXR;*.GIF;*.HDR;*.IFF;*.JPEG;*.JPG;*.PGM;*.PNG;*.POT;*.PPM;*.SYS;*.TGA;*.TIFF", 1346 # options={'HIDDEN'}, 1347 # ) 1348 quality: IntProperty( 1349 name="Quality", description="", default=100, min=1, max=100 1350 ) 1351 hf_filename: StringProperty(maxlen=1024) 1352 1353 hf_gamma: FloatProperty( 1354 name="Gamma", description="Gamma", min=0.0001, max=20.0, default=1.0 1355 ) 1356 1357 hf_premultiplied: BoolProperty( 1358 name="Premultiplied", description="Premultiplied", default=True 1359 ) 1360 1361 hf_smooth: BoolProperty(name="Smooth", description="Smooth", default=False) 1362 1363 hf_water: FloatProperty( 1364 name="Water Level", 1365 description="Wather Level", 1366 min=0.00, 1367 max=1.00, 1368 default=0.0, 1369 ) 1370 1371 hf_hierarchy: BoolProperty( 1372 name="Hierarchy", description="Height field hierarchy", default=True 1373 ) 1374 1375 def execute(self, context): 1376 props = self.properties 1377 impath = bpy.path.abspath(self.filepath) 1378 img = bpy.data.images.load(impath) 1379 im_name = img.name 1380 im_name, file_extension = os.path.splitext(im_name) 1381 hf_tex = bpy.data.textures.new('%s_hf_image' % im_name, type='IMAGE') 1382 hf_tex.image = img 1383 mat = bpy.data.materials.new('Tex_%s_hf' % im_name) 1384 hf_slot = mat.pov_texture_slots.add() 1385 hf_slot.texture = hf_tex.name 1386 # layers = 20*[False] 1387 # layers[0] = True 1388 quality = props.quality 1389 res = 100 / quality 1390 w, h = hf_tex.image.size[:] 1391 w = int(w / res) 1392 h = int(h / res) 1393 bpy.ops.mesh.primitive_grid_add( 1394 x_subdivisions=w, y_subdivisions=h, size=0.5 1395 ) 1396 ob = context.object 1397 ob.name = ob.data.name = '%s' % im_name 1398 ob.data.materials.append(mat) 1399 bpy.ops.object.mode_set(mode="EDIT") 1400 # bpy.ops.mesh.noise(factor=1) # TODO replace by a displace modifier as noise deprecated in 2.8 1401 bpy.ops.object.mode_set(mode="OBJECT") 1402 1403 # needs a loop to select by index? 1404 # bpy.ops.object.material_slot_remove() 1405 # material just left there for now 1406 1407 mat.pov_texture_slots.clear() 1408 bpy.ops.object.mode_set(mode="EDIT") 1409 bpy.ops.mesh.hide(unselected=False) 1410 bpy.ops.object.mode_set(mode="OBJECT") 1411 ob.pov.object_as = 'HEIGHT_FIELD' 1412 ob.pov.hf_filename = impath 1413 return {'FINISHED'} 1414 1415 1416############################TORUS############################################ 1417def pov_torus_define(context, op, ob): 1418 """Add the representation of POV torus using just a Blender torus. 1419 1420 But flag its primitive type with a specific pov.object_as attribute and lock edit mode 1421 to keep proxy consistency by hiding edit geometry.""" 1422 1423 if op: 1424 mas = op.mas 1425 mis = op.mis 1426 mar = op.mar 1427 mir = op.mir 1428 else: 1429 assert ob 1430 mas = ob.pov.torus_major_segments 1431 mis = ob.pov.torus_minor_segments 1432 mar = ob.pov.torus_major_radius 1433 mir = ob.pov.torus_minor_radius 1434 1435 # keep object rotation and location for the add object operator 1436 obrot = ob.rotation_euler 1437 obloc = ob.location 1438 1439 bpy.ops.object.mode_set(mode="EDIT") 1440 bpy.ops.mesh.reveal() 1441 bpy.ops.mesh.select_all(action='SELECT') 1442 bpy.ops.mesh.delete(type='VERT') 1443 bpy.ops.mesh.primitive_torus_add( 1444 rotation=obrot, 1445 location=obloc, 1446 major_segments=mas, 1447 minor_segments=mis, 1448 major_radius=mar, 1449 minor_radius=mir, 1450 ) 1451 1452 bpy.ops.mesh.hide(unselected=False) 1453 bpy.ops.object.mode_set(mode="OBJECT") 1454 1455 if not ob: 1456 bpy.ops.mesh.primitive_torus_add( 1457 major_segments=mas, 1458 minor_segments=mis, 1459 major_radius=mar, 1460 minor_radius=mir, 1461 ) 1462 ob = context.object 1463 ob.name = ob.data.name = "PovTorus" 1464 ob.pov.object_as = "TORUS" 1465 ob.pov.torus_major_segments = mas 1466 ob.pov.torus_minor_segments = mis 1467 ob.pov.torus_major_radius = mar 1468 ob.pov.torus_minor_radius = mir 1469 bpy.ops.object.mode_set(mode="EDIT") 1470 bpy.ops.mesh.hide(unselected=False) 1471 bpy.ops.object.mode_set(mode="OBJECT") 1472 1473 1474class POVRAY_OT_torus_add(Operator): 1475 """Add the representation of POV torus using using pov_torus_define() function.""" 1476 1477 bl_idname = "pov.addtorus" 1478 bl_label = "Torus" 1479 bl_description = "Add Torus" 1480 bl_options = {'REGISTER', 'UNDO'} 1481 1482 # XXX Keep it in sync with __init__'s torus Primitive 1483 mas: IntProperty( 1484 name="Major Segments", description="", default=48, min=3, max=720 1485 ) 1486 mis: IntProperty( 1487 name="Minor Segments", description="", default=12, min=3, max=720 1488 ) 1489 mar: FloatProperty(name="Major Radius", description="", default=1.0) 1490 mir: FloatProperty(name="Minor Radius", description="", default=0.25) 1491 1492 def execute(self, context): 1493 props = self.properties 1494 mar = props.mar 1495 mir = props.mir 1496 mas = props.mas 1497 mis = props.mis 1498 pov_torus_define(context, self, None) 1499 self.report( 1500 {'INFO'}, 1501 "This native POV-Ray primitive " 1502 "won't have any vertex to show in edit mode", 1503 ) 1504 return {'FINISHED'} 1505 1506 1507class POVRAY_OT_torus_update(Operator): 1508 """Update the POV torus. 1509 1510 Delete its previous proxy geometry and rerun pov_torus_define() function 1511 with the new parameters""" 1512 1513 bl_idname = "pov.torus_update" 1514 bl_label = "Update" 1515 bl_description = "Update Torus" 1516 bl_options = {'REGISTER', 'UNDO'} 1517 COMPAT_ENGINES = {'POVRAY_RENDER'} 1518 1519 @classmethod 1520 def poll(cls, context): 1521 engine = context.scene.render.engine 1522 ob = context.object 1523 return ( 1524 ob 1525 and ob.data 1526 and ob.type == 'MESH' 1527 and engine in cls.COMPAT_ENGINES 1528 ) 1529 1530 def execute(self, context): 1531 1532 pov_torus_define(context, None, context.object) 1533 1534 return {'FINISHED'} 1535 1536 1537################################################################################### 1538 1539 1540class POVRAY_OT_prism_add(Operator): 1541 """Add the representation of POV prism using using an extruded curve.""" 1542 1543 bl_idname = "pov.addprism" 1544 bl_label = "Prism" 1545 bl_description = "Create Prism" 1546 bl_options = {'REGISTER', 'UNDO'} 1547 1548 prism_n: IntProperty( 1549 name="Sides", description="Number of sides", default=5, min=3, max=720 1550 ) 1551 prism_r: FloatProperty(name="Radius", description="Radius", default=1.0) 1552 1553 def execute(self, context): 1554 1555 props = self.properties 1556 loftData = bpy.data.curves.new('Prism', type='CURVE') 1557 loftData.dimensions = '2D' 1558 loftData.resolution_u = 2 1559 # loftData.show_normal_face = False 1560 loftData.extrude = 2 1561 n = props.prism_n 1562 r = props.prism_r 1563 coords = [] 1564 z = 0 1565 angle = 0 1566 for p in range(n): 1567 x = r * cos(angle) 1568 y = r * sin(angle) 1569 coords.append((x, y, z)) 1570 angle += pi * 2 / n 1571 poly = loftData.splines.new('POLY') 1572 poly.points.add(len(coords) - 1) 1573 for i, coord in enumerate(coords): 1574 x, y, z = coord 1575 poly.points[i].co = (x, y, z, 1) 1576 poly.use_cyclic_u = True 1577 1578 ob = bpy.data.objects.new('Prism_shape', loftData) 1579 scn = bpy.context.scene 1580 scn.collection.objects.link(ob) 1581 context.view_layer.objects.active = ob 1582 ob.select_set(True) 1583 ob.pov.curveshape = "prism" 1584 ob.name = ob.data.name = "Prism" 1585 return {'FINISHED'} 1586 1587 1588##############################PARAMETRIC###################################### 1589def pov_parametric_define(context, op, ob): 1590 """Add the representation of POV parametric surfaces by math surface from add mesh extra objects addon.""" 1591 1592 if op: 1593 u_min = op.u_min 1594 u_max = op.u_max 1595 v_min = op.v_min 1596 v_max = op.v_max 1597 x_eq = op.x_eq 1598 y_eq = op.y_eq 1599 z_eq = op.z_eq 1600 1601 else: 1602 assert ob 1603 u_min = ob.pov.u_min 1604 u_max = ob.pov.u_max 1605 v_min = ob.pov.v_min 1606 v_max = ob.pov.v_max 1607 x_eq = ob.pov.x_eq 1608 y_eq = ob.pov.y_eq 1609 z_eq = ob.pov.z_eq 1610 1611 # keep object rotation and location for the updated object 1612 obloc = ob.location 1613 obrot = ob.rotation_euler # In radians 1614 # Parametric addon has no loc rot, some extra work is needed 1615 # in case cursor has moved 1616 curloc = bpy.context.scene.cursor.location 1617 1618 bpy.ops.object.mode_set(mode="EDIT") 1619 bpy.ops.mesh.reveal() 1620 bpy.ops.mesh.select_all(action='SELECT') 1621 bpy.ops.mesh.delete(type='VERT') 1622 bpy.ops.mesh.primitive_xyz_function_surface( 1623 x_eq=x_eq, 1624 y_eq=y_eq, 1625 z_eq=z_eq, 1626 range_u_min=u_min, 1627 range_u_max=u_max, 1628 range_v_min=v_min, 1629 range_v_max=v_max, 1630 ) 1631 bpy.ops.mesh.select_all(action='SELECT') 1632 # extra work: 1633 bpy.ops.transform.translate(value=(obloc - curloc), proportional_size=1) 1634 bpy.ops.transform.rotate(axis=obrot, proportional_size=1) 1635 1636 bpy.ops.mesh.hide(unselected=False) 1637 bpy.ops.object.mode_set(mode="OBJECT") 1638 1639 if not ob: 1640 bpy.ops.mesh.primitive_xyz_function_surface( 1641 x_eq=x_eq, 1642 y_eq=y_eq, 1643 z_eq=z_eq, 1644 range_u_min=u_min, 1645 range_u_max=u_max, 1646 range_v_min=v_min, 1647 range_v_max=v_max, 1648 ) 1649 ob = context.object 1650 ob.name = ob.data.name = "PovParametric" 1651 ob.pov.object_as = "PARAMETRIC" 1652 1653 ob.pov.u_min = u_min 1654 ob.pov.u_max = u_max 1655 ob.pov.v_min = v_min 1656 ob.pov.v_max = v_max 1657 ob.pov.x_eq = x_eq 1658 ob.pov.y_eq = y_eq 1659 ob.pov.z_eq = z_eq 1660 1661 bpy.ops.object.mode_set(mode="EDIT") 1662 bpy.ops.mesh.hide(unselected=False) 1663 bpy.ops.object.mode_set(mode="OBJECT") 1664 1665 1666class POVRAY_OT_parametric_add(Operator): 1667 """Add the representation of POV parametric surfaces using pov_parametric_define() function.""" 1668 1669 bl_idname = "pov.addparametric" 1670 bl_label = "Parametric" 1671 bl_description = "Add Paramertic" 1672 bl_options = {'REGISTER', 'UNDO'} 1673 1674 # XXX Keep it in sync with __init__'s Parametric primitive 1675 u_min: FloatProperty(name="U Min", description="", default=0.0) 1676 v_min: FloatProperty(name="V Min", description="", default=0.0) 1677 u_max: FloatProperty(name="U Max", description="", default=6.28) 1678 v_max: FloatProperty(name="V Max", description="", default=12.57) 1679 x_eq: StringProperty(maxlen=1024, default="cos(v)*(1+cos(u))*sin(v/8)") 1680 y_eq: StringProperty(maxlen=1024, default="sin(u)*sin(v/8)+cos(v/8)*1.5") 1681 z_eq: StringProperty(maxlen=1024, default="sin(v)*(1+cos(u))*sin(v/8)") 1682 1683 def execute(self, context): 1684 props = self.properties 1685 u_min = props.u_min 1686 v_min = props.v_min 1687 u_max = props.u_max 1688 v_max = props.v_max 1689 x_eq = props.x_eq 1690 y_eq = props.y_eq 1691 z_eq = props.z_eq 1692 1693 pov_parametric_define(context, self, None) 1694 self.report( 1695 {'INFO'}, 1696 "This native POV-Ray primitive " 1697 "won't have any vertex to show in edit mode", 1698 ) 1699 return {'FINISHED'} 1700 1701 1702class POVRAY_OT_parametric_update(Operator): 1703 """Update the representation of POV parametric surfaces. 1704 1705 Delete its previous proxy geometry and rerun pov_parametric_define() function 1706 with the new parameters""" 1707 1708 bl_idname = "pov.parametric_update" 1709 bl_label = "Update" 1710 bl_description = "Update parametric object" 1711 bl_options = {'REGISTER', 'UNDO'} 1712 COMPAT_ENGINES = {'POVRAY_RENDER'} 1713 1714 @classmethod 1715 def poll(cls, context): 1716 engine = context.scene.render.engine 1717 ob = context.object 1718 return ( 1719 ob 1720 and ob.data 1721 and ob.type == 'MESH' 1722 and engine in cls.COMPAT_ENGINES 1723 ) 1724 1725 def execute(self, context): 1726 1727 pov_parametric_define(context, None, context.object) 1728 1729 return {'FINISHED'} 1730 1731 1732####################################################################### 1733 1734 1735class POVRAY_OT_shape_polygon_to_circle_add(Operator): 1736 """Add the proxy mesh for POV Polygon to circle lofting macro""" 1737 1738 bl_idname = "pov.addpolygontocircle" 1739 bl_label = "Polygon To Circle Blending" 1740 bl_description = "Add Polygon To Circle Blending Surface" 1741 bl_options = {'REGISTER', 'UNDO'} 1742 COMPAT_ENGINES = {'POVRAY_RENDER'} 1743 1744 # XXX Keep it in sync with __init__'s polytocircle properties 1745 polytocircle_resolution: IntProperty( 1746 name="Resolution", description="", default=3, min=0, max=256 1747 ) 1748 polytocircle_ngon: IntProperty( 1749 name="NGon", description="", min=3, max=64, default=5 1750 ) 1751 polytocircle_ngonR: FloatProperty( 1752 name="NGon Radius", description="", default=0.3 1753 ) 1754 polytocircle_circleR: FloatProperty( 1755 name="Circle Radius", description="", default=1.0 1756 ) 1757 1758 def execute(self, context): 1759 props = self.properties 1760 ngon = props.polytocircle_ngon 1761 ngonR = props.polytocircle_ngonR 1762 circleR = props.polytocircle_circleR 1763 resolution = props.polytocircle_resolution 1764 # layers = 20*[False] 1765 # layers[0] = True 1766 bpy.ops.mesh.primitive_circle_add( 1767 vertices=ngon, radius=ngonR, fill_type='NGON', enter_editmode=True 1768 ) 1769 bpy.ops.transform.translate(value=(0, 0, 1)) 1770 bpy.ops.mesh.subdivide(number_cuts=resolution) 1771 numCircleVerts = ngon + (ngon * resolution) 1772 bpy.ops.mesh.select_all(action='DESELECT') 1773 bpy.ops.mesh.primitive_circle_add( 1774 vertices=numCircleVerts, 1775 radius=circleR, 1776 fill_type='NGON', 1777 enter_editmode=True, 1778 ) 1779 bpy.ops.transform.translate(value=(0, 0, -1)) 1780 bpy.ops.mesh.select_all(action='SELECT') 1781 bpy.ops.mesh.bridge_edge_loops() 1782 if ngon < 5: 1783 bpy.ops.mesh.select_all(action='DESELECT') 1784 bpy.ops.mesh.primitive_circle_add( 1785 vertices=ngon, 1786 radius=ngonR, 1787 fill_type='TRIFAN', 1788 enter_editmode=True, 1789 ) 1790 bpy.ops.transform.translate(value=(0, 0, 1)) 1791 bpy.ops.mesh.select_all(action='SELECT') 1792 bpy.ops.mesh.remove_doubles() 1793 bpy.ops.object.mode_set(mode='OBJECT') 1794 ob = context.object 1795 ob.name = "Polygon_To_Circle" 1796 ob.pov.object_as = 'POLYCIRCLE' 1797 ob.pov.ngon = ngon 1798 ob.pov.ngonR = ngonR 1799 ob.pov.circleR = circleR 1800 bpy.ops.object.mode_set(mode="EDIT") 1801 bpy.ops.mesh.hide(unselected=False) 1802 bpy.ops.object.mode_set(mode="OBJECT") 1803 return {'FINISHED'} 1804 1805 1806#############################IMPORT 1807 1808 1809class ImportPOV(bpy.types.Operator, ImportHelper): 1810 """Load Povray files""" 1811 1812 bl_idname = "import_scene.pov" 1813 bl_label = "POV-Ray files (.pov/.inc)" 1814 bl_options = {'PRESET', 'UNDO'} 1815 COMPAT_ENGINES = {'POVRAY_RENDER'} 1816 1817 # ----------- 1818 # File props. 1819 files: CollectionProperty( 1820 type=bpy.types.OperatorFileListElement, options={'HIDDEN', 'SKIP_SAVE'} 1821 ) 1822 directory: StringProperty( 1823 maxlen=1024, subtype='FILE_PATH', options={'HIDDEN', 'SKIP_SAVE'} 1824 ) 1825 1826 filename_ext = {".pov", ".inc"} 1827 filter_glob: StringProperty(default="*.pov;*.inc", options={'HIDDEN'}) 1828 1829 import_at_cur: BoolProperty( 1830 name="Import at Cursor Location", 1831 description="Ignore Object Matrix", 1832 default=False, 1833 ) 1834 1835 def execute(self, context): 1836 from mathutils import Matrix 1837 1838 verts = [] 1839 faces = [] 1840 materials = [] 1841 blendMats = [] ############## 1842 povMats = [] ############## 1843 colors = [] 1844 matNames = [] 1845 lenverts = None 1846 lenfaces = None 1847 suffix = -1 1848 name = 'Mesh2_%s' % suffix 1849 name_search = False 1850 verts_search = False 1851 faces_search = False 1852 plane_search = False 1853 box_search = False 1854 cylinder_search = False 1855 sphere_search = False 1856 cone_search = False 1857 tex_search = False ################## 1858 cache = [] 1859 matrixes = {} 1860 writematrix = False 1861 index = None 1862 value = None 1863 # filepov = bpy.path.abspath(self.filepath) #was used for single files 1864 1865 def mat_search(cache): 1866 r = g = b = 0.5 1867 f = t = 0 1868 color = None 1869 1870 for item, value in enumerate(cache): 1871 1872 if value == 'texture': 1873 pass 1874 1875 if value == 'pigment': 1876 1877 if cache[item + 2] in {'rgb', 'srgb'}: 1878 pass 1879 1880 elif cache[item + 2] in {'rgbf', 'srgbf'}: 1881 pass 1882 1883 elif cache[item + 2] in {'rgbt', 'srgbt'}: 1884 try: 1885 r, g, b, t = ( 1886 float(cache[item + 3]), 1887 float(cache[item + 4]), 1888 float(cache[item + 5]), 1889 float(cache[item + 6]), 1890 ) 1891 except: 1892 r = g = b = t = float(cache[item + 2]) 1893 color = (r, g, b, t) 1894 1895 elif cache[item + 2] in {'rgbft', 'srgbft'}: 1896 pass 1897 1898 else: 1899 pass 1900 1901 if colors == [] or (colors != [] and color not in colors): 1902 colors.append(color) 1903 name = ob.name + "_mat" 1904 matNames.append(name) 1905 mat = bpy.data.materials.new(name) 1906 mat.diffuse_color = (r, g, b) 1907 mat.alpha = 1 - t 1908 if mat.alpha != 1: 1909 mat.use_transparency = True 1910 ob.data.materials.append(mat) 1911 1912 else: 1913 for i, value in enumerate(colors): 1914 if color == value: 1915 ob.data.materials.append( 1916 bpy.data.materials[matNames[i]] 1917 ) 1918 1919 for file in self.files: 1920 print("Importing file: " + file.name) 1921 filepov = self.directory + file.name 1922 for line in open(filepov): 1923 string = line.replace("{", " ") 1924 string = string.replace("}", " ") 1925 string = string.replace("<", " ") 1926 string = string.replace(">", " ") 1927 string = string.replace(",", " ") 1928 lw = string.split() 1929 lenwords = len(lw) 1930 if lw: 1931 if lw[0] == "object": 1932 writematrix = True 1933 if writematrix: 1934 if lw[0] not in {"object", "matrix"}: 1935 index = lw[0] 1936 if lw[0] in {"matrix"}: 1937 value = [ 1938 float(lw[1]), 1939 float(lw[2]), 1940 float(lw[3]), 1941 float(lw[4]), 1942 float(lw[5]), 1943 float(lw[6]), 1944 float(lw[7]), 1945 float(lw[8]), 1946 float(lw[9]), 1947 float(lw[10]), 1948 float(lw[11]), 1949 float(lw[12]), 1950 ] 1951 matrixes[index] = value 1952 writematrix = False 1953 for line in open(filepov): 1954 S = line.replace("{", " { ") 1955 S = S.replace("}", " } ") 1956 S = S.replace(",", " ") 1957 S = S.replace("<", "") 1958 S = S.replace(">", " ") 1959 S = S.replace("=", " = ") 1960 S = S.replace(";", " ; ") 1961 S = S.split() 1962 lenS = len(S) 1963 for i, word in enumerate(S): 1964 ##################Primitives Import################## 1965 if word == 'cone': 1966 cone_search = True 1967 name_search = False 1968 if cone_search: 1969 cache.append(word) 1970 if cache[-1] == '}': 1971 try: 1972 x0 = float(cache[2]) 1973 y0 = float(cache[3]) 1974 z0 = float(cache[4]) 1975 r0 = float(cache[5]) 1976 x1 = float(cache[6]) 1977 y1 = float(cache[7]) 1978 z1 = float(cache[8]) 1979 r1 = float(cache[9]) 1980 # Y is height in most pov files, not z 1981 bpy.ops.pov.cone_add( 1982 base=r0, cap=r1, height=(y1 - y0) 1983 ) 1984 ob = context.object 1985 ob.location = (x0, y0, z0) 1986 # ob.scale = (r,r,r) 1987 mat_search(cache) 1988 except (ValueError): 1989 pass 1990 cache = [] 1991 cone_search = False 1992 if word == 'plane': 1993 plane_search = True 1994 name_search = False 1995 if plane_search: 1996 cache.append(word) 1997 if cache[-1] == '}': 1998 try: 1999 bpy.ops.pov.addplane() 2000 ob = context.object 2001 mat_search(cache) 2002 except (ValueError): 2003 pass 2004 cache = [] 2005 plane_search = False 2006 if word == 'box': 2007 box_search = True 2008 name_search = False 2009 if box_search: 2010 cache.append(word) 2011 if cache[-1] == '}': 2012 try: 2013 x0 = float(cache[2]) 2014 y0 = float(cache[3]) 2015 z0 = float(cache[4]) 2016 x1 = float(cache[5]) 2017 y1 = float(cache[6]) 2018 z1 = float(cache[7]) 2019 # imported_corner_1=(x0, y0, z0) 2020 # imported_corner_2 =(x1, y1, z1) 2021 center = ( 2022 (x0 + x1) / 2, 2023 (y0 + y1) / 2, 2024 (z0 + z1) / 2, 2025 ) 2026 bpy.ops.pov.addbox() 2027 ob = context.object 2028 ob.location = center 2029 mat_search(cache) 2030 2031 except (ValueError): 2032 pass 2033 cache = [] 2034 box_search = False 2035 if word == 'cylinder': 2036 cylinder_search = True 2037 name_search = False 2038 if cylinder_search: 2039 cache.append(word) 2040 if cache[-1] == '}': 2041 try: 2042 x0 = float(cache[2]) 2043 y0 = float(cache[3]) 2044 z0 = float(cache[4]) 2045 x1 = float(cache[5]) 2046 y1 = float(cache[6]) 2047 z1 = float(cache[7]) 2048 imported_cyl_loc = (x0, y0, z0) 2049 imported_cyl_loc_cap = (x1, y1, z1) 2050 2051 r = float(cache[8]) 2052 2053 vec = Vector(imported_cyl_loc_cap) - Vector( 2054 imported_cyl_loc 2055 ) 2056 depth = vec.length 2057 rot = Vector((0, 0, 1)).rotation_difference( 2058 vec 2059 ) # Rotation from Z axis. 2060 trans = rot @ Vector( 2061 (0, 0, depth / 2) 2062 ) # Such that origin is at center of the base of the cylinder. 2063 # center = ((x0 + x1)/2,(y0 + y1)/2,(z0 + z1)/2) 2064 scaleZ = ( 2065 sqrt( 2066 (x1 - x0) ** 2 2067 + (y1 - y0) ** 2 2068 + (z1 - z0) ** 2 2069 ) 2070 / 2 2071 ) 2072 bpy.ops.pov.addcylinder( 2073 R=r, 2074 imported_cyl_loc=imported_cyl_loc, 2075 imported_cyl_loc_cap=imported_cyl_loc_cap, 2076 ) 2077 ob = context.object 2078 ob.location = (x0, y0, z0) 2079 ob.rotation_euler = rot.to_euler() 2080 ob.scale = (1, 1, scaleZ) 2081 2082 # scale data rather than obj? 2083 # bpy.ops.object.mode_set(mode='EDIT') 2084 # bpy.ops.mesh.reveal() 2085 # bpy.ops.mesh.select_all(action='SELECT') 2086 # bpy.ops.transform.resize(value=(1,1,scaleZ), orient_type='LOCAL') 2087 # bpy.ops.mesh.hide(unselected=False) 2088 # bpy.ops.object.mode_set(mode='OBJECT') 2089 2090 mat_search(cache) 2091 2092 except (ValueError): 2093 pass 2094 cache = [] 2095 cylinder_search = False 2096 if word == 'sphere': 2097 sphere_search = True 2098 name_search = False 2099 if sphere_search: 2100 cache.append(word) 2101 if cache[-1] == '}': 2102 x = y = z = r = 0 2103 try: 2104 x = float(cache[2]) 2105 y = float(cache[3]) 2106 z = float(cache[4]) 2107 r = float(cache[5]) 2108 2109 except (ValueError): 2110 pass 2111 except: 2112 x = y = z = float(cache[2]) 2113 r = float(cache[3]) 2114 bpy.ops.pov.addsphere(R=r, imported_loc=(x, y, z)) 2115 ob = context.object 2116 ob.location = (x, y, z) 2117 ob.scale = (r, r, r) 2118 mat_search(cache) 2119 cache = [] 2120 sphere_search = False 2121 ##################End Primitives Import################## 2122 if word == '#declare': 2123 name_search = True 2124 if name_search: 2125 cache.append(word) 2126 if word == 'mesh2': 2127 name_search = False 2128 if cache[-2] == '=': 2129 name = cache[-3] 2130 else: 2131 suffix += 1 2132 cache = [] 2133 if word in {'texture', ';'}: 2134 name_search = False 2135 cache = [] 2136 if word == 'vertex_vectors': 2137 verts_search = True 2138 if verts_search: 2139 cache.append(word) 2140 if word == '}': 2141 verts_search = False 2142 lenverts = cache[2] 2143 cache.pop() 2144 cache.pop(0) 2145 cache.pop(0) 2146 cache.pop(0) 2147 for i in range(int(lenverts)): 2148 x = i * 3 2149 y = (i * 3) + 1 2150 z = (i * 3) + 2 2151 verts.append( 2152 ( 2153 float(cache[x]), 2154 float(cache[y]), 2155 float(cache[z]), 2156 ) 2157 ) 2158 cache = [] 2159 # if word == 'face_indices': 2160 # faces_search = True 2161 if word == 'texture_list': ######## 2162 tex_search = True ####### 2163 if tex_search: ######### 2164 if ( 2165 word 2166 not in { 2167 'texture_list', 2168 'texture', 2169 '{', 2170 '}', 2171 'face_indices', 2172 } 2173 and word.isdigit() == False 2174 ): ############## 2175 povMats.append(word) ################# 2176 if word == 'face_indices': 2177 tex_search = False ################ 2178 faces_search = True 2179 if faces_search: 2180 cache.append(word) 2181 if word == '}': 2182 faces_search = False 2183 lenfaces = cache[2] 2184 cache.pop() 2185 cache.pop(0) 2186 cache.pop(0) 2187 cache.pop(0) 2188 lf = int(lenfaces) 2189 var = int(len(cache) / lf) 2190 for i in range(lf): 2191 if var == 3: 2192 v0 = i * 3 2193 v1 = i * 3 + 1 2194 v2 = i * 3 + 2 2195 faces.append( 2196 ( 2197 int(cache[v0]), 2198 int(cache[v1]), 2199 int(cache[v2]), 2200 ) 2201 ) 2202 if var == 4: 2203 v0 = i * 4 2204 v1 = i * 4 + 1 2205 v2 = i * 4 + 2 2206 m = i * 4 + 3 2207 materials.append((int(cache[m]))) 2208 faces.append( 2209 ( 2210 int(cache[v0]), 2211 int(cache[v1]), 2212 int(cache[v2]), 2213 ) 2214 ) 2215 if var == 6: 2216 v0 = i * 6 2217 v1 = i * 6 + 1 2218 v2 = i * 6 + 2 2219 m0 = i * 6 + 3 2220 m1 = i * 6 + 4 2221 m2 = i * 6 + 5 2222 materials.append( 2223 ( 2224 int(cache[m0]), 2225 int(cache[m1]), 2226 int(cache[m2]), 2227 ) 2228 ) 2229 faces.append( 2230 ( 2231 int(cache[v0]), 2232 int(cache[v1]), 2233 int(cache[v2]), 2234 ) 2235 ) 2236 # mesh = pov_define_mesh(None, verts, [], faces, name, hide_geometry=False) 2237 # ob = object_utils.object_data_add(context, mesh, operator=None) 2238 2239 me = bpy.data.meshes.new(name) ######## 2240 ob = bpy.data.objects.new(name, me) ########## 2241 bpy.context.collection.objects.link(ob) ######### 2242 me.from_pydata(verts, [], faces) ############ 2243 2244 for mat in bpy.data.materials: ############## 2245 blendMats.append(mat.name) ############# 2246 for mName in povMats: ##################### 2247 if mName not in blendMats: ########### 2248 povMat = bpy.data.materials.new( 2249 mName 2250 ) ################# 2251 mat_search(cache) 2252 ob.data.materials.append( 2253 bpy.data.materials[mName] 2254 ) ################### 2255 if materials: ################## 2256 for i, val in enumerate( 2257 materials 2258 ): #################### 2259 try: ################### 2260 ob.data.polygons[ 2261 i 2262 ].material_index = ( 2263 val 2264 ) #################### 2265 except TypeError: ################### 2266 ob.data.polygons[ 2267 i 2268 ].material_index = int( 2269 val[0] 2270 ) ################## 2271 2272 blendMats = [] ######################### 2273 povMats = [] ######################### 2274 materials = [] ######################### 2275 cache = [] 2276 name_search = True 2277 if name in matrixes and self.import_at_cur == False: 2278 global_matrix = Matrix.Rotation( 2279 pi / 2.0, 4, 'X' 2280 ) 2281 ob = bpy.context.object 2282 matrix = ob.matrix_world 2283 v = matrixes[name] 2284 matrix[0][0] = v[0] 2285 matrix[1][0] = v[1] 2286 matrix[2][0] = v[2] 2287 matrix[0][1] = v[3] 2288 matrix[1][1] = v[4] 2289 matrix[2][1] = v[5] 2290 matrix[0][2] = v[6] 2291 matrix[1][2] = v[7] 2292 matrix[2][2] = v[8] 2293 matrix[0][3] = v[9] 2294 matrix[1][3] = v[10] 2295 matrix[2][3] = v[11] 2296 matrix = global_matrix * ob.matrix_world 2297 ob.matrix_world = matrix 2298 verts = [] 2299 faces = [] 2300 2301 # if word == 'pigment': 2302 # try: 2303 # #all indices have been incremented once to fit a bad test file 2304 # r,g,b,t = float(S[2]),float(S[3]),float(S[4]),float(S[5]) 2305 # color = (r,g,b,t) 2306 2307 # except (IndexError): 2308 # #all indices have been incremented once to fit alternate test file 2309 # r,g,b,t = float(S[3]),float(S[4]),float(S[5]),float(S[6]) 2310 # color = (r,g,b,t) 2311 # except UnboundLocalError: 2312 # # In case no transmit is specified ? put it to 0 2313 # r,g,b,t = float(S[2]),float(S[3]),float(S[4],0) 2314 # color = (r,g,b,t) 2315 2316 # except (ValueError): 2317 # color = (0.8,0.8,0.8,0) 2318 # pass 2319 2320 # if colors == [] or (colors != [] and color not in colors): 2321 # colors.append(color) 2322 # name = ob.name+"_mat" 2323 # matNames.append(name) 2324 # mat = bpy.data.materials.new(name) 2325 # mat.diffuse_color = (r,g,b) 2326 # mat.alpha = 1-t 2327 # if mat.alpha != 1: 2328 # mat.use_transparency=True 2329 # ob.data.materials.append(mat) 2330 # print (colors) 2331 # else: 2332 # for i in range(len(colors)): 2333 # if color == colors[i]: 2334 # ob.data.materials.append(bpy.data.materials[matNames[i]]) 2335 2336 ##To keep Avogadro Camera angle: 2337 # for obj in bpy.context.view_layer.objects: 2338 # if obj.type == "CAMERA": 2339 # track = obj.constraints.new(type = "TRACK_TO") 2340 # track.target = ob 2341 # track.track_axis ="TRACK_NEGATIVE_Z" 2342 # track.up_axis = "UP_Y" 2343 # obj.location = (0,0,0) 2344 return {'FINISHED'} 2345 2346 2347classes = ( 2348 POVRAY_OT_lathe_add, 2349 POVRAY_OT_superellipsoid_add, 2350 POVRAY_OT_superellipsoid_update, 2351 POVRAY_OT_supertorus_add, 2352 POVRAY_OT_supertorus_update, 2353 POVRAY_OT_loft_add, 2354 POVRAY_OT_plane_add, 2355 POVRAY_OT_box_add, 2356 POVRAY_OT_cylinder_add, 2357 POVRAY_OT_cylinder_update, 2358 POVRAY_OT_sphere_add, 2359 POVRAY_OT_sphere_update, 2360 POVRAY_OT_cone_add, 2361 POVRAY_OT_cone_update, 2362 POVRAY_OT_isosurface_box_add, 2363 POVRAY_OT_isosurface_sphere_add, 2364 POVRAY_OT_sphere_sweep_add, 2365 POVRAY_OT_blob_add, 2366 POVRAY_OT_rainbow_add, 2367 POVRAY_OT_height_field_add, 2368 POVRAY_OT_torus_add, 2369 POVRAY_OT_torus_update, 2370 POVRAY_OT_prism_add, 2371 POVRAY_OT_parametric_add, 2372 POVRAY_OT_parametric_update, 2373 POVRAY_OT_shape_polygon_to_circle_add, 2374 ImportPOV, 2375) 2376 2377 2378def register(): 2379 # from bpy.utils import register_class 2380 2381 for cls in classes: 2382 register_class(cls) 2383 2384 2385def unregister(): 2386 from bpy.utils import unregister_class 2387 2388 for cls in classes: 2389 unregister_class(cls) 2390