1# -*- coding: utf-8 -*- 2# 3# Copyright (C) 2015,2016 Thorsten Liebig (Thorsten.Liebig@gmx.de) 4# 5# This program is free software: you can redistribute it and/or modify 6# it under the terms of the GNU Lesser General Public License as published 7# by the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU Lesser General Public License for more details. 14# 15# You should have received a copy of the GNU Lesser General Public License 16# along with this program. If not, see <http://www.gnu.org/licenses/>. 17# 18 19"""CSXCAD.CSPrimitives 20Module for all Primitives 21 22Notes 23----- 24Usually it is not meant to create primitives manually, but instead 25use the ContinuousStructure object to create primives using the 26e.g. AddBox or AddCylinder methods. 27 28Examples 29-------- 30Create a metal box: 31 32>>> pset = ParameterObjects.ParameterSet() 33>>> metal = CSProperties.CSPropMetal(pset) 34>>> box = CSPrimitives.CSPrimBox(pset, metal) 35""" 36 37import numpy as np 38import sys 39from libcpp.string cimport string 40from libcpp cimport bool 41 42cimport CSPrimitives 43from Utilities import CheckNyDir, GetMultiDirs 44cimport CSRectGrid 45 46cdef class CSPrimitives: 47 """ 48 Virtual base class for all primives, cannot be created! 49 50 """ 51 @staticmethod 52 def fromType(prim_type, pset, prop, no_init=False, **kw): 53 """ fromType(prim_type, pset, prop, no_init=False, **kw) 54 55 Create a primtive specified by the `prim_type` 56 57 :param prim_type: Primitive type 58 :param pset: ParameterSet to assign to the new primitive 59 :param prop: CSProperty to assign to the new primitive 60 :param no_init: do not create an actual C++ instance 61 """ 62 prim = None 63 if prim_type == POINT: 64 prim = CSPrimPoint(pset, prop, no_init=no_init, **kw) 65 elif prim_type == POINT: 66 prim = CSPrimPoint(pset, prop, no_init=no_init, **kw) 67 elif prim_type == BOX: 68 prim = CSPrimBox(pset, prop, no_init=no_init, **kw) 69 elif prim_type == MULTIBOX: 70 raise Exception('Primitive type "MULTIBOX" not yet implemented!') 71 elif prim_type == SPHERE: 72 prim = CSPrimSphere(pset, prop, no_init=no_init, **kw) 73 elif prim_type == SPHERICALSHELL: 74 prim = CSPrimSphericalShell(pset, prop, no_init=no_init, **kw) 75 elif prim_type == CYLINDER: 76 prim = CSPrimCylinder(pset, prop, no_init=no_init, **kw) 77 elif prim_type == CYLINDRICALSHELL: 78 prim = CSPrimCylindricalShell(pset, prop, no_init=no_init, **kw) 79 elif prim_type == POLYGON: 80 prim = CSPrimPolygon(pset, prop, no_init=no_init, **kw) 81 elif prim_type == LINPOLY: 82 prim = CSPrimLinPoly(pset, prop, no_init=no_init, **kw) 83 elif prim_type == ROTPOLY: 84 prim = CSPrimRotPoly(pset, prop, no_init=no_init, **kw) 85 elif prim_type == POLYHEDRON: 86 prim = CSPrimPolyhedron(pset, prop, no_init=no_init, **kw) 87 elif prim_type == CURVE: 88 prim = CSPrimCurve(pset, prop, no_init=no_init, **kw) 89 elif prim_type == WIRE: 90 prim = CSPrimWire(pset, prop, no_init=no_init, **kw) 91 elif prim_type == USERDEFINED: 92 raise Exception('Primitive type "USERDEFINED" not yet implemented!') 93 elif prim_type == POLYHEDRONREADER: 94 prim = CSPrimPolyhedronReader(pset, prop, no_init=no_init, **kw) 95 return prim 96 97 def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw): 98 self.__transform = None 99 self.__prop = prop 100 if no_init: 101 self.thisptr = NULL 102 return 103 104 assert self.thisptr, 'Error, object cannot be created (protected)' 105 self.__prop = prop 106 107 if 'priority' in kw: 108 self.SetPriority(kw['priority']) 109 del kw['priority'] 110 if 'no_init' in kw: 111 del kw['no_init'] 112 113 assert len(kw)==0, 'Unknown keyword arguments: "{}"'.format(kw) 114 115 def GetID(self): 116 """ 117 Get the ID for this primitive 118 119 :returns: int -- ID for this primitive 120 """ 121 return self.thisptr.GetID() 122 123 def GetProperty(self): 124 """ 125 Get the property for this primitive 126 127 :returns: CSProperties.CSProperties 128 """ 129 return self.__GetProperty() 130 131 cdef __GetProperty(self): 132 cdef _CSProperties* _prop 133 cdef CSProperties prop 134 if self.__prop is None: 135 _prop = self.thisptr.GetProperty() 136 self.__prop = CSProperties.fromType(_prop.GetType(), pset=None, no_init=True) 137 self.__prop.thisptr = _prop 138 139 return self.__prop 140 141 def GetType(self): 142 """ 143 Get the type as int for this primitive 144 145 :returns: int -- Type for this primitive (e.g. 0 --> Point, 1 --> Box, ...) 146 """ 147 return self.thisptr.GetType() 148 149 def GetTypeName(self): 150 """ 151 Get the type as string (UTF-8) for this primitive 152 153 :returns: str -- Type name for this primitive ("Point", "Box", ...) 154 """ 155 return self.thisptr.GetTypeName().decode('UTF-8') 156 157 def SetPriority(self, val): 158 """ SetPriority(val) 159 160 Set the priority for this primitive 161 162 :param val: int -- Higher priority values will override primitives with a lower priority 163 """ 164 self.thisptr.SetPriority(val) 165 166 def GetPriority(self): 167 """ 168 Get the priority for this primitive 169 170 :returns: int -- Priority for this primitive 171 """ 172 return self.thisptr.GetPriority() 173 174 def GetBoundBox(self): 175 """ 176 Get the bounding box for this primitive 177 178 :returns: (2,3) ndarray -- bounding box for this primitive 179 """ 180 bb = np.zeros([2,3]) 181 cdef double _bb[6] 182 self.thisptr.GetBoundBox(_bb) 183 for n in range(3): 184 bb[0,n] = _bb[2*n] 185 bb[1,n] = _bb[2*n+1] 186 return bb 187 188 def GetDimension(self): 189 """ 190 Get the dimension of this primitive 191 192 :returns: int -- dimension 0..3 193 """ 194 return self.thisptr.GetDimension() 195 196 def IsInside(self, coord, tol=0): 197 """ IsInside(coord, tol=0) 198 199 Check if a given coordinate is inside this primitive. 200 201 :param coord: (3,) array -- coordinate 202 :returns: bool 203 """ 204 cdef double c_coord[3] 205 for n in range(3): 206 c_coord[n] = coord[n] 207 208 return self.thisptr.IsInside(c_coord, tol) 209 210 def GetPrimitiveUsed(self): 211 """ 212 Get if this primitive has been used (used flag set) 213 """ 214 return self.thisptr.GetPrimitiveUsed() 215 216 def SetPrimitiveUsed(self, val): 217 """ SetPrimitiveUsed(val) 218 219 Set used flag. 220 """ 221 self.thisptr.SetPrimitiveUsed(val) 222 223 def __GetCSX(self): 224 if self.__prop is None: 225 return None 226 return self.__prop.__CSX 227 228 def GetTransform(self): 229 """ GetTransform() 230 231 Get the transformation class assigned to this primitive. 232 If this primitve does not have any, it will be created. 233 234 :return: CSTransform class 235 236 See Also 237 -------- 238 CSXCAD.CSTransform.CSTransform 239 """ 240 if self.__transform is None: 241 self.__transform = CSTransform(no_init=True) 242 self.__transform.thisptr = self.thisptr.GetTransform() 243 return self.__transform 244 245 def AddTransform(self, transform, *args, no_init=False, **kw): 246 """ AddTransform(transform, *args, **kw) 247 248 Add a transformation to this primitive. 249 250 See Also 251 -------- 252 CSXCAD.CSTransform.CSTransform.AddTransform 253 """ 254 tr = self.GetTransform() 255 tr.AddTransform(transform, *args, **kw) 256 257 def HasTransform(self): 258 """ 259 Check if this primitive has a transformation attached. 260 It will not create one if it does not. 261 262 :returns: bool 263 """ 264 if self.__transform is None: 265 return False 266 return self.__transform.HasTransform() 267 268 def SetCoordinateSystem(self, cs_type): 269 """ SetCoordinateSystem(cs_type) 270 271 Set the coordinate system type (Cartesian or cylindrical) for this primitive. 272 If set to None, the mesh type of the assigned rect grid will be used. 273 274 :param cs_type: coordinate system (0 : Cartesian, 1 : Cylindrical) or None 275 276 See Also 277 -------- 278 CSXCAD.CSRectGrid.CSRectGrid.SetMeshType 279 280 """ 281 assert cs_type in [CSRectGrid.CARTESIAN, CSRectGrid.CYLINDRICAL, None], 'Unknown coordinate system: {}'.format(cs_type) 282 if cs_type is None: 283 cs_type = CSRectGrid.UNDEFINED_CS 284 self.thisptr.SetCoordinateSystem(cs_type) 285 286 def GetCoordinateSystem(self): 287 """ GetCoordinateSystem 288 289 :returns: coordinate system (0 : Cartesian, 1 : Cylindrical) or None 290 """ 291 cs_type = self.thisptr.GetCoordinateSystem() 292 if cs_type == CSRectGrid.UNDEFINED_CS: 293 return None 294 return cs_type 295 296 def Update(self): 297 """ Trigger an internal update and report success and error message 298 299 :returns: bool, err_msg -- success and error message (empty on success) 300 """ 301 cdef string s 302 succ = self.thisptr.Update(&s) 303 return succ, str(s) 304 305 306############################################################################### 307cdef class CSPrimPoint(CSPrimitives): 308 """ Point Primitive 309 310 A point is defined by a single 3D coordinate. 311 312 Parameters 313 ---------- 314 coord : (vector) 315 Coordinate vector (3,) array 316 317 """ 318 def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw): 319 if no_init: 320 self.thisptr = NULL 321 return 322 if not self.thisptr: 323 self.thisptr = new _CSPrimPoint(pset.thisptr, prop.thisptr) 324 325 if 'coord' in kw: 326 self.SetCoord(kw['coord']) 327 del kw['coord'] 328 super(CSPrimPoint, self).__init__(pset, prop, *args, **kw) 329 330 def SetCoord(self, coord): 331 """ SetCoord(coord) 332 333 Set the coordinate for this point primitive 334 335 :param coord: list/array of float -- Set the point coordinate 336 """ 337 ptr = <_CSPrimPoint*>self.thisptr 338 assert len(coord)==3, "CSPrimPoint:SetCoord: length of array needs to be 3" 339 for n in range(3): 340 ptr.SetCoord(n, coord[n]) 341 342 def GetCoord(self): 343 """ 344 Get the point coordinate for this primitive 345 346 :returns: (3,) ndarray -- point coordinate for this primitive 347 """ 348 ptr = <_CSPrimPoint*>self.thisptr 349 coord = np.zeros(3) 350 for n in range(3): 351 coord[n] = ptr.GetCoord(n) 352 return coord 353 354############################################################################### 355cdef class CSPrimBox(CSPrimitives): 356 """ Box Primitive 357 358 A box is defined by two 3D coordinates. E.g. the lower-left (start) 359 and upper right (stop) point. 360 A box is a cube in Cartesian coordinates. 361 A box is a cylinder in cylindrical coordinates. 362 363 Parameters 364 ---------- 365 start : (3,) array 366 Start point vector (3,) array 367 stop : (3,) array 368 Stop point vector (3,) array 369 370 """ 371 def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw): 372 if no_init: 373 self.thisptr = NULL 374 return 375 if not self.thisptr: 376 self.thisptr = new _CSPrimBox(pset.thisptr, prop.thisptr) 377 if 'start' in kw: 378 self.SetStart(kw['start']) 379 del kw['start'] 380 if 'stop' in kw: 381 self.SetStop(kw['stop']) 382 del kw['stop'] 383 super(CSPrimBox, self).__init__(pset, prop, *args, **kw) 384 385 def SetStart(self, coord): 386 """ SetStart(coord) 387 388 Set the start coordinate for this box primitive. 389 390 :param coord: list/array of float -- Set the start point coordinate 391 """ 392 ptr = <_CSPrimBox*>self.thisptr 393 assert len(coord)==3, "CSPrimBox:SetStart: length of array needs to be 3" 394 for n in range(3): 395 ptr.SetCoord(2*n, coord[n]) 396 397 def SetStop(self, coord): 398 """ SetStop(coord) 399 400 Set the stop coordinate for this box primitive. 401 402 :param coord: list/array of float -- Set the stop point coordinate 403 """ 404 ptr = <_CSPrimBox*>self.thisptr 405 assert len(coord)==3, "CSPrimBox:SetStop: length of array needs to be 3" 406 for n in range(3): 407 ptr.SetCoord(2*n+1, coord[n]) 408 409 def GetStart(self): 410 """ 411 Get the start coordinate for this primitive. 412 413 :returns: (3,) ndarray -- Start coordinate for this primitive 414 """ 415 ptr = <_CSPrimBox*>self.thisptr 416 coord = np.zeros(3) 417 for n in range(3): 418 coord[n] = ptr.GetCoord(2*n) 419 return coord 420 421 def GetStop(self): 422 """ 423 Get the stop coordinate for this primitive. 424 425 :returns: (3,) ndarray -- Stop coordinate for this primitive 426 """ 427 ptr = <_CSPrimBox*>self.thisptr 428 coord = np.zeros(3) 429 for n in range(3): 430 coord[n] = ptr.GetCoord(2*n+1) 431 return coord 432 433############################################################################### 434cdef class CSPrimCylinder(CSPrimitives): 435 """ Cylinder Primitive 436 437 A cylinder is defined by its axis and a radius. 438 The axis is defined by two 3D coordinates (start/stop). 439 440 Parameters 441 ---------- 442 start : (3,) array 443 Axis start point vector (3,) array 444 stop : (3,) array 445 Axis stop point vector (3,) array 446 radius : float 447 The cylinder radius 448 449 """ 450 def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw): 451 if no_init: 452 self.thisptr = NULL 453 return 454 if not self.thisptr: 455 self.thisptr = new _CSPrimCylinder(pset.thisptr, prop.thisptr) 456 if 'start' in kw: 457 self.SetStart(kw['start']) 458 del kw['start'] 459 if 'stop' in kw: 460 self.SetStop(kw['stop']) 461 del kw['stop'] 462 if 'radius' in kw: 463 self.SetRadius(kw['radius']) 464 del kw['radius'] 465 super(CSPrimCylinder, self).__init__(pset, prop, *args, **kw) 466 467 def SetStart(self, coord): 468 """ SetStart(coord) 469 470 Set the start coordinate for the cylinder axis. 471 472 :param coord: list/array of float -- Set the axis start point coordinate. 473 """ 474 ptr = <_CSPrimCylinder*>self.thisptr 475 assert len(coord)==3, "CSPrimCylinder:SetStart: length of array needs to be 3" 476 for n in range(3): 477 ptr.SetCoord(2*n, coord[n]) 478 479 def SetStop(self, coord): 480 """ SetStop(coord) 481 482 Set the stop coordinate for the cylinder axis. 483 484 :param coord: list/array of float -- Set the axis stop point coordinate. 485 """ 486 ptr = <_CSPrimCylinder*>self.thisptr 487 assert len(coord)==3, "CSPrimCylinder:SetStop: length of array needs to be 3" 488 for n in range(3): 489 ptr.SetCoord(2*n+1, coord[n]) 490 491 def GetStart(self): 492 """ 493 Get the axis start coordinate. 494 495 :returns: (3,) ndarray -- Axis start coordinate. 496 """ 497 ptr = <_CSPrimCylinder*>self.thisptr 498 coord = np.zeros(3) 499 for n in range(3): 500 coord[n] = ptr.GetCoord(2*n) 501 return coord 502 503 def GetStop(self): 504 """ 505 Get the axis stop coordinate. 506 507 :returns: (3,) ndarray -- Axis stop coordinate. 508 """ 509 ptr = <_CSPrimCylinder*>self.thisptr 510 coord = np.zeros(3) 511 for n in range(3): 512 coord[n] = ptr.GetCoord(2*n+1) 513 return coord 514 515 def SetRadius(self, val): 516 """ SetRadius(val) 517 518 Set the cylinder radius 519 520 :param val: float -- Set the cylinder radius 521 """ 522 ptr = <_CSPrimCylinder*>self.thisptr 523 ptr.SetRadius(val) 524 525 def GetRadius(self): 526 """ 527 Get the cylinder radius. 528 529 :returns: float -- Cylinder radius. 530 """ 531 ptr = <_CSPrimCylinder*>self.thisptr 532 return ptr.GetRadius() 533 534############################################################################### 535cdef class CSPrimCylindricalShell(CSPrimCylinder): 536 """ Cylindrical Shell (hollow cylinder) 537 538 A cylindrical shell is defined like a cylinder with an additional shell width. 539 540 Parameters 541 ---------- 542 shell_width : float 543 Width of the cylindrical shell 544 545 """ 546 def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw): 547 if no_init: 548 self.thisptr = NULL 549 return 550 if not self.thisptr: 551 self.thisptr = new _CSPrimCylindricalShell(pset.thisptr, prop.thisptr) 552 if 'shell_width' in kw: 553 self.SetShellWidth(kw['shell_width']) 554 del kw['shell_width'] 555 super(CSPrimCylindricalShell, self).__init__(pset, prop, *args, **kw) 556 557 def SetShellWidth(self, val): 558 """ SetShellWidth(val) 559 560 Set the cylinder shell width. 561 562 :param val: float -- Set the cylinder shell width 563 """ 564 ptr = <_CSPrimCylindricalShell*>self.thisptr 565 ptr.SetShellWidth(val) 566 567 def GetShellWidth(self): 568 """ 569 Get the cylinder shell width. 570 571 :returns: float -- Cylinder shell width. 572 """ 573 ptr = <_CSPrimCylindricalShell*>self.thisptr 574 return ptr.GetShellWidth() 575 576############################################################################### 577cdef class CSPrimSphere(CSPrimitives): 578 """ Sphere Primitive 579 580 A sphere is defined by its center and radius. 581 The center is defined by a 3D coordinate. 582 583 Parameters 584 ---------- 585 center : (3,) array 586 Center point vector (3,) array 587 radius : float 588 The sphere radius 589 590 """ 591 def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw): 592 if no_init: 593 self.thisptr = NULL 594 return 595 if not self.thisptr: 596 self.thisptr = new _CSPrimSphere(pset.thisptr, prop.thisptr) 597 if 'center' in kw: 598 self.SetCenter(kw['center']) 599 del kw['center'] 600 if 'radius' in kw: 601 self.SetRadius(kw['radius']) 602 del kw['radius'] 603 super(CSPrimSphere, self).__init__(pset, prop, *args, **kw) 604 605 def SetCenter(self, coord): 606 """ SetRadius(val) 607 608 Set the sphere center point. 609 610 :param coord: (3,) array -- Set the sphere center point. 611 """ 612 ptr = <_CSPrimSphere*>self.thisptr 613 assert len(coord)==3, "CSPrimSphere:SetCenter: length of array needs to be 3" 614 ptr.SetCenter(coord[0], coord[1], coord[2]) 615 616 def GetCenter(self): 617 """ 618 Get the sphere center point. 619 620 :returns: (3,) ndarray -- Center coordinate. 621 """ 622 ptr = <_CSPrimSphere*>self.thisptr 623 coord = np.zeros(3) 624 for n in range(3): 625 coord[n] = ptr.GetCoord(n) 626 return coord 627 628 def SetRadius(self, val): 629 """ SetRadius(val) 630 631 Set the sphere radius 632 633 :param val: float -- Set the sphere radius 634 """ 635 ptr = <_CSPrimSphere*>self.thisptr 636 ptr.SetRadius(val) 637 638 def GetRadius(self): 639 """ 640 Get the sphere radius. 641 642 :returns: float -- Sphere radius. 643 """ 644 ptr = <_CSPrimSphere*>self.thisptr 645 return ptr.GetRadius() 646 647############################################################################### 648cdef class CSPrimSphericalShell(CSPrimSphere): 649 """ Spherical Shell (hollow sphere) Primitive Class 650 651 A spherical shell is defined like a sphere with an additional shell width. 652 653 Parameters 654 ---------- 655 shell_width : float 656 Width of the spherical shell 657 658 """ 659 def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw): 660 if no_init: 661 self.thisptr = NULL 662 return 663 if not self.thisptr: 664 self.thisptr = new _CSPrimSphericalShell(pset.thisptr, prop.thisptr) 665 if 'shell_width' in kw: 666 self.SetShellWidth(kw['shell_width']) 667 del kw['shell_width'] 668 super(CSPrimSphericalShell, self).__init__(pset, prop, *args, **kw) 669 670 def SetShellWidth(self, val): 671 """ SetShellWidth(val) 672 673 Set the sphere shell width. 674 675 :param val: float -- Set the sphere shell width 676 """ 677 ptr = <_CSPrimSphericalShell*>self.thisptr 678 ptr.SetShellWidth(val) 679 680 def GetShellWidth(self): 681 """ 682 Get the sphere shell width. 683 684 :returns: float -- sphere shell width. 685 """ 686 ptr = <_CSPrimSphericalShell*>self.thisptr 687 return ptr.GetShellWidth() 688 689############################################################################### 690cdef class CSPrimPolygon(CSPrimitives): 691 """ Polygon Primitive 692 693 A polygon is a surface defined by a set of 2D points/coordinates. 694 To place the polygon in a 3D space, a normal direction (x/y/z) and an 695 elevation in this direction have to be specified. 696 697 Parameters 698 ---------- 699 points : (N,2) array 700 Array of coordinates 701 norm_dir : float or str 702 Normal direction, either 0,1,2 or x/y/z respectively 703 elevation : float 704 Elevation in normal direciton 705 706 Examples 707 -------- 708 Define a half circle as polygon 709 710 >>> polygon = CSPrimitives.CSPrimBox(pset, metal, norm_dir='z', elevation=1.0) 711 >>> ang = np.linspace(0, np.pi, 21) 712 >>> polygon.SetCoords(5*np.cos(ang), 5*np.sin(ang)) 713 """ 714 def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw): 715 if no_init: 716 self.thisptr = NULL 717 return 718 if not self.thisptr: 719 self.thisptr = new _CSPrimPolygon(pset.thisptr, prop.thisptr) 720 if 'points' in kw: 721 assert len(kw['points'])==2, 'points must be a list of length 2' 722 self.SetCoords(kw['points'][0], kw['points'][1]) 723 del kw['points'] 724 if 'norm_dir' in kw: 725 self.SetNormDir(kw['norm_dir']) 726 del kw['norm_dir'] 727 if 'elevation' in kw: 728 self.SetElevation(kw['elevation']) 729 del kw['elevation'] 730 super(CSPrimPolygon, self).__init__(pset, prop, *args, **kw) 731 732 def SetCoords(self, x0, x1): 733 """ SetCoords(x0, x1) 734 735 Set the coordinates for the polygon. This will clear all previous coordinates. 736 737 :param x0, x1: (N,), (N,) Two arrays for x0/x1 of the polygon coordinates. 738 """ 739 assert len(x0)==len(x1), 'SetCoords: x0/x1 do not have the same length' 740 assert len(x0)>0, 'SetCoords: empty coordinates' 741 742 ptr = <_CSPrimPolygon*>self.thisptr 743 ptr.ClearCoords() 744 for n in range(len(x0)): 745 ptr.AddCoord(x0[n]) 746 ptr.AddCoord(x1[n]) 747 748 def GetCoords(self): 749 """ 750 Get the coordinates for the polygon 751 752 :return x0, x1: (N,), (N,) Arrays for x0,x1 of the polygon coordinates 753 """ 754 ptr = <_CSPrimPolygon*>self.thisptr 755 N = ptr.GetQtyCoords() 756 x0 = np.zeros(N) 757 x1 = np.zeros(N) 758 for n in range(N): 759 x0[n] = ptr.GetCoord(2*n) 760 x1[n] = ptr.GetCoord(2*n+1) 761 return x0, x1 762 763 def GetQtyCoords(self): 764 """ 765 Get the number of coordinates for the polygon 766 767 :return val: int -- Number of polygon coordinates. 768 """ 769 ptr = <_CSPrimPolygon*>self.thisptr 770 return ptr.GetQtyCoords() 771 772 def ClearCoords(self): 773 """ 774 Remove all coordinates. 775 """ 776 ptr = <_CSPrimPolygon*>self.thisptr 777 ptr.ClearCoords() 778 779 def SetNormDir(self, ny): 780 """ SetNormDir(ny) 781 782 Set the normal direction. 783 784 :param ny: int or string -- Normal direction, either 0/1/2 or 'x'/'y'/'z' 785 """ 786 ptr = <_CSPrimPolygon*>self.thisptr 787 ptr.SetNormDir(CheckNyDir(ny)) 788 789 def GetNormDir(self): 790 """ 791 Get the normal direction. 792 793 :return ny: int -- Normal direction as 0, 1 or 2 meaning x,y or z 794 """ 795 ptr = <_CSPrimPolygon*>self.thisptr 796 return ptr.GetNormDir() 797 798 def SetElevation(self, val): 799 """ SetElevation(val) 800 801 Set the elevation in normal direction. 802 803 :param val: float -- Elevation in normal direction. 804 """ 805 ptr = <_CSPrimPolygon*>self.thisptr 806 ptr.SetElevation(val) 807 808 def GetElevation(self): 809 """ 810 Get the elevation in normal direction. 811 812 :return val: float -- Get the elevation in normal direction. 813 """ 814 ptr = <_CSPrimPolygon*>self.thisptr 815 return ptr.GetElevation() 816 817############################################################################### 818cdef class CSPrimLinPoly(CSPrimPolygon): 819 """ Linear Extruded Polygon 820 821 A linear extruded polygon is a polygon that is extruded in normal direction 822 for a certain length above the elevation. 823 824 Parameters 825 ---------- 826 length : float 827 Extrusion length in normal direction 828 829 Examples 830 -------- 831 Define a half circle with a height (in z direction) of 1 832 833 >>> linpoly = CSPrimitives.CSPrimLinPoly(pset, metal, norm_dir='z', elevation=0.5) 834 >>> ang = np.linspace(0, np.pi, 21) 835 >>> linpoly.SetCoords(5*np.cos(ang), 5*np.sin(ang)) 836 >>> linpoly.SetLength(1.0) 837 """ 838 def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw): 839 if no_init: 840 self.thisptr = NULL 841 return 842 if not self.thisptr: 843 self.thisptr = new _CSPrimLinPoly(pset.thisptr, prop.thisptr) 844 if 'length' in kw: 845 self.SetLength(kw['length']) 846 del kw['length'] 847 super(CSPrimLinPoly, self).__init__(pset, prop, *args, **kw) 848 849 def SetLength(self, val): 850 """ SetLength(val) 851 852 Set the extrusion length in normal direction. 853 854 :param val: float -- Extrusion length in normal direction. 855 """ 856 ptr = <_CSPrimLinPoly*>self.thisptr 857 ptr.SetLength(val) 858 859 def GetLength(self): 860 """ 861 Get the extrusion length in normal direction. 862 863 :return val: float -- Get the extrusion length in normal direction. 864 """ 865 ptr = <_CSPrimLinPoly*>self.thisptr 866 return ptr.GetLength() 867 868############################################################################### 869cdef class CSPrimRotPoly(CSPrimPolygon): 870 """ Rotation Extruded Polygon 871 872 A rotation extruded polygon is a polygon that is rotated around a Cartesian 873 axis with a given start and stop angle. 874 875 Parameters 876 ---------- 877 rot_axis : float or str 878 Rotation axis direction, either 0,1,2 or x/y/z respectively. 879 angle : float, float 880 Start/Stop angle (rad) of rotation. Default is (0, 2*pi). 881 882 Examples 883 -------- 884 Define a half circle on the xy-plane, rotated around the x axis 885 886 >>> rotpoly = CSPrimitives.CSPrimRotPoly(pset, metal, norm_dir='z') 887 >>> ang = np.linspace(0, np.pi, 21) 888 >>> rotpoly.SetCoords(5*np.cos(ang), 5*np.sin(ang)) 889 >>> rotpoly.SetRotAxisDir('x') 890 """ 891 def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw): 892 if no_init: 893 self.thisptr = NULL 894 return 895 if not self.thisptr: 896 self.thisptr = new _CSPrimRotPoly(pset.thisptr, prop.thisptr) 897 if 'rot_axis' in kw: 898 self.SetRotAxisDir(kw['rot_axis']) 899 del kw['rot_axis'] 900 if 'angle' in kw: 901 assert len(kw['angle'])==2, 'angle must be a list/array of length 2' 902 self.SetAngle(kw['angle'][0],kw['angle'][1]) 903 del kw['angle'] 904 super(CSPrimRotPoly, self).__init__(pset, prop, *args, **kw) 905 906 def SetRotAxisDir(self, ny): 907 """ SetRotAxisDir(ny) 908 909 Set the rotation axis direction, either 0,1,2 or x/y/z respectively. 910 911 :param ny: int or str -- Rotation axis direction, either 0,1,2 or x/y/z respectively. 912 """ 913 ptr = <_CSPrimRotPoly*>self.thisptr 914 ptr.SetRotAxisDir(CheckNyDir(ny)) 915 916 def GetRotAxisDir(self): 917 """ 918 Get the rotation axis direction 919 920 :returns ny: int -- Rotation axis direction as 0, 1 or 2 meaning x,y or z 921 """ 922 ptr = <_CSPrimRotPoly*>self.thisptr 923 return ptr.GetRotAxisDir() 924 925 def SetAngle(self, a0, a1): 926 """ SetAngle(a0, a1) 927 928 Set the start/stop angle (rad) of rotation. Default is (0, 2*pi). 929 930 :param a0: float -- Start angle (rad) of rotation. 931 :param a1: float -- Stop angle (rad) of rotation. 932 """ 933 ptr = <_CSPrimRotPoly*>self.thisptr 934 ptr.SetAngle(0, a0) 935 ptr.SetAngle(1, a1) 936 937 def GetAngle(self): 938 """ 939 Get the start/stop angle (rad) of rotation. 940 941 :returns a0, a1: float, float -- Start/Stop angle (rad) of rotation. 942 """ 943 ptr = <_CSPrimRotPoly*>self.thisptr 944 return ptr.GetAngle(0), ptr.GetAngle(1) 945 946############################################################################### 947cdef class CSPrimCurve(CSPrimitives): 948 """ Curve Primitive 949 950 A curve is a set of consequtive 3D coordinates. 951 952 Parameters 953 ---------- 954 points : (3, N) array 955 Array of 3D coordinates. 956 957 Examples 958 -------- 959 960 >>> x = np.array([0, 0, 1, 1]) + 1.5 961 >>> y = np.array([0, 1, 1, 0]) + 2.5 962 >>> z = np.array([0, 1, 3, 4]) 963 >>> curve = CSPrimitives.CSPrimCurve(pset, metal, points=[x,y,z]) 964 >>> curve.AddPoint([2, 0, 5]) 965 """ 966 def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw): 967 if no_init: 968 self.thisptr = NULL 969 return 970 if not self.thisptr: 971 self.thisptr = new _CSPrimCurve(pset.thisptr, prop.thisptr) 972 if 'points' in kw: 973 assert len(kw['points'])==3, 'points list not of length 3' 974 self.SetPoints(kw['points'][0], kw['points'][1], kw['points'][2]) 975 del kw['points'] 976 super(CSPrimCurve, self).__init__(pset, prop, *args, **kw) 977 978 def AddPoint(self, point): 979 """ AddPoint(point) 980 981 Add a single point to the list. 982 983 :param point: (3,) array -- Add a single 3D point 984 """ 985 assert len(point)==3, "CSPrimSphere:SetCenter: length of array needs to be 3" 986 ptr = <_CSPrimCurve*>self.thisptr 987 cdef double dp[3] 988 for n in range(3): 989 dp[n] = point[n] 990 ptr.AddPoint(dp) 991 992 def SetPoints(self, x, y, z): 993 """ SetPoints(x, y, z) 994 995 Set an array of 3D coordinates 996 997 :param x,y,z: each (N,) array -- Array of 3D point components 998 """ 999 assert len(x)==len(y)==len(z), 'SetPoints: each component must be of equal length' 1000 assert len(x)>0, 'SetPoints: empty list!' 1001 ptr = <_CSPrimCurve*>self.thisptr 1002 ptr.ClearPoints() 1003 cdef double dp[3] 1004 for n in range(len(x)): 1005 dp[0] = x[n] 1006 dp[1] = y[n] 1007 dp[2] = z[n] 1008 ptr.AddPoint(dp) 1009 1010 def GetPoint(self, idx): 1011 """ GetPoint(idx) 1012 1013 Get a point with a given index. 1014 1015 :param idx: int -- Index of point requested. 1016 :return point: (3,) array -- Point coordinate at index `idx` 1017 """ 1018 ptr = <_CSPrimCurve*>self.thisptr 1019 cdef double dp[3] 1020 assert ptr.GetPoint(idx, dp), 'GetPoint: invalid index' 1021 point = np.zeros(3) 1022 for n in range(3): 1023 point[n] = dp[n] 1024 return point 1025 1026 def ClearPoints(self): 1027 """ 1028 Clear all points. 1029 """ 1030 ptr = <_CSPrimCurve*>self.thisptr 1031 ptr.ClearPoints() 1032 1033 def GetNumberOfPoints(self): 1034 """ 1035 Get the number of points. 1036 1037 :return num: int -- Get the number of points. 1038 """ 1039 ptr = <_CSPrimCurve*>self.thisptr 1040 return ptr.GetNumberOfPoints() 1041 1042 1043############################################################################### 1044cdef class CSPrimWire(CSPrimCurve): 1045 """ Wire Primitive 1046 1047 A wire is a curve with a given radius. 1048 1049 Parameters 1050 ---------- 1051 radius : float 1052 Wire radius 1053 """ 1054 def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw): 1055 if no_init: 1056 self.thisptr = NULL 1057 return 1058 if not self.thisptr: 1059 self.thisptr = new _CSPrimWire(pset.thisptr, prop.thisptr) 1060 if 'radius' in kw: 1061 self.SetWireRadius(kw['radius']) 1062 del kw['radius'] 1063 super(CSPrimWire, self).__init__(pset, prop, *args, **kw) 1064 1065 1066 def SetWireRadius(self, val): 1067 """ SetWireRadius(val) 1068 1069 Set the wire radius 1070 1071 :param val: float -- Set the wire radius 1072 """ 1073 ptr = <_CSPrimWire*>self.thisptr 1074 ptr.SetWireRadius(val) 1075 1076 def GetWireRadius(self): 1077 """ 1078 Get the wire radius. 1079 1080 :returns: float -- Wire radius. 1081 """ 1082 ptr = <_CSPrimWire*>self.thisptr 1083 return ptr.GetWireRadius() 1084 1085############################################################################### 1086cdef class CSPrimPolyhedron(CSPrimitives): 1087 """ Polyhedron Primitive 1088 1089 A polyhedron is a 3D solid with flat polygonal faces (currently only triangles). 1090 1091 """ 1092 def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw): 1093 if no_init: 1094 self.thisptr = NULL 1095 return 1096 if not self.thisptr: 1097 self.thisptr = new _CSPrimPolyhedron(pset.thisptr, prop.thisptr) 1098 super(CSPrimPolyhedron, self).__init__(pset, prop, *args, **kw) 1099 1100 def Reset(self): 1101 """ 1102 Reset the polyhedron, that means removeing all faces. 1103 """ 1104 ptr = <_CSPrimPolyhedron*>self.thisptr 1105 ptr.Reset() 1106 1107 def AddVertex(self, x, y, z): 1108 """ AddVertex(x, y, z) 1109 1110 Add a single 3D vertex. 1111 1112 :param x,y,z: float,float,float -- 3D vertex 1113 """ 1114 ptr = <_CSPrimPolyhedron*>self.thisptr 1115 ptr.AddVertex(x, y, z) 1116 1117 def GetVertex(self, idx): 1118 """ GetVertex(idx) 1119 1120 Get the vertex with index `idx`. 1121 1122 :param idx: int -- Vertex index to return 1123 :returns point: (3,) array -- Vertex coordinate at index `idx` 1124 """ 1125 ptr = <_CSPrimPolyhedron*>self.thisptr 1126 assert idx>=0 and idx<ptr.GetNumVertices(), "Error: invalid vertex index" 1127 cdef float* p 1128 p = ptr.GetVertex(idx) 1129 assert p!=NULL 1130 pyp = np.zeros(3) 1131 for n in range(3): 1132 pyp[n] = p[n] 1133 return pyp 1134 1135 def GetNumVertices(self): 1136 """ 1137 Get the number of vertices. 1138 1139 :returns num: int -- Number of vertices 1140 """ 1141 ptr = <_CSPrimPolyhedron*>self.thisptr 1142 return ptr.GetNumVertices() 1143 1144 def AddFace(self, verts): 1145 """ AddFace(verts) 1146 1147 Add a face with a given list of vertices. 1148 The vertices have to be added already. 1149 Currently only triangle faces are possible. 1150 1151 :params verts: (N,) array -- Face with N vericies (currently N=3!) 1152 """ 1153 assert len(verts)==3, 'AddFace: currently only triangles allowed as faces' 1154 cdef int i_v[3] 1155 for n in range(3): 1156 i_v[n] = verts[n] 1157 ptr = <_CSPrimPolyhedron*>self.thisptr 1158 ptr.AddFace(len(verts), i_v) 1159 1160 def GetFace(self, idx): 1161 """ GetFace(idx) 1162 1163 Get the face vertex indicies for the given face index `idx` 1164 1165 :param idx: int -- Face index to return 1166 :returns: (N,) array -- Vertices array for face with index `idx` 1167 """ 1168 ptr = <_CSPrimPolyhedron*>self.thisptr 1169 assert idx>=0 and idx<ptr.GetNumFaces(), "Error: invalid face index" 1170 cdef int *i_v 1171 cdef unsigned int numVert=0 1172 i_v = ptr.GetFace(idx, numVert) 1173 assert i_v!=NULL 1174 face = np.zeros(numVert, np.int) 1175 for n in range(numVert): 1176 face[n] = i_v[n] 1177 return face 1178 1179 def GetNumFaces(self): 1180 """ 1181 Get the number of faces. 1182 1183 :return num: int -- number of faces 1184 """ 1185 ptr = <_CSPrimPolyhedron*>self.thisptr 1186 return ptr.GetNumFaces() 1187 1188############################################################################### 1189cdef class CSPrimPolyhedronReader(CSPrimPolyhedron): 1190 """ Polyhedron Reader 1191 1192 This primives creates a polyhedron by reading a STL or PLY file. 1193 1194 Parameters 1195 ---------- 1196 filename : str 1197 File name to read 1198 """ 1199 def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw): 1200 if no_init: 1201 self.thisptr = NULL 1202 return 1203 if not self.thisptr: 1204 self.thisptr = new _CSPrimPolyhedronReader(pset.thisptr, prop.thisptr) 1205 if 'filename' in kw: 1206 self.SetFilename(kw['filename']) 1207 del kw['filename'] 1208 super(CSPrimPolyhedronReader, self).__init__(pset, prop, *args, **kw) 1209 1210 def SetFilename(self, fn): 1211 """ SetFilename(fn) 1212 1213 Set the file name to read. This will try set the propper file type as well. 1214 1215 :param fn: str -- File name to read 1216 """ 1217 ptr = <_CSPrimPolyhedronReader*>self.thisptr 1218 if fn.endswith('.stl'): 1219 self.SetFileType(1) 1220 elif fn.endswith('.ply'): 1221 self.SetFileType(2) 1222 else: 1223 self.SetFileType(0) 1224 ptr.SetFilename(fn.encode('UTF-8')) 1225 1226 def GetFilename(self): 1227 """ 1228 Get the file name. 1229 1230 :returns fn: str -- File name to read 1231 """ 1232 ptr = <_CSPrimPolyhedronReader*>self.thisptr 1233 return ptr.GetFilename() 1234 1235 def SetFileType(self, t): 1236 """ SetFileType(t) 1237 1238 Set the file type. 1 --> STL-File, 2 --> PLY, 0 --> other/unknown 1239 1240 :param t: int -- File type (see above) 1241 """ 1242 ptr = <_CSPrimPolyhedronReader*>self.thisptr 1243 ptr.SetFileType(t) 1244 1245 def GetFileType(self): 1246 """ 1247 Get the file type. 1 --> STL-File, 2 --> PLY, 0 --> other/unknown 1248 1249 :return t: int -- File type (see above) 1250 """ 1251 ptr = <_CSPrimPolyhedronReader*>self.thisptr 1252 return ptr.GetFileType() 1253 1254 def ReadFile(self): 1255 """ 1256 Issue to read the file. 1257 1258 :return succ: bool -- True on successful read 1259 """ 1260 ptr = <_CSPrimPolyhedronReader*>self.thisptr 1261 return ptr.ReadFile() 1262