|
1 | 1 | from paraview.simple import * |
2 | 2 | from paraview.util.vtkAlgorithm import * |
3 | 3 | from vtkmodules.numpy_interface import dataset_adapter as dsa |
4 | | -from vtkmodules.vtkCommonCore import vtkPoints |
| 4 | +from vtkmodules.vtkCommonCore import ( |
| 5 | + vtkPoints, |
| 6 | + vtkIdList, |
| 7 | +) |
5 | 8 | from vtkmodules.vtkCommonDataModel import ( |
6 | 9 | vtkPolyData, |
7 | 10 | vtkCellArray, |
8 | 11 | vtkPlane, |
9 | 12 | ) |
10 | 13 | from vtkmodules.vtkCommonTransforms import vtkTransform |
11 | | -from vtkmodules.vtkFiltersCore import vtkAppendFilter |
| 14 | +from vtkmodules.vtkFiltersCore import ( |
| 15 | + vtkAppendFilter, |
| 16 | + vtkGenerateIds, |
| 17 | +) |
12 | 18 | from vtkmodules.vtkFiltersGeneral import ( |
13 | 19 | vtkTransformFilter, |
14 | 20 | vtkTableBasedClipDataSet, |
@@ -52,7 +58,6 @@ def ProcessPoint(point, radius): |
52 | 58 | z = rho * math.cos(math.radians(phi)) |
53 | 59 | return [x, y, z] |
54 | 60 |
|
55 | | - |
56 | 61 | @smproxy.filter() |
57 | 62 | @smproperty.input(name="Input") |
58 | 63 | @smdomain.datatype( |
@@ -408,74 +413,192 @@ def RequestData(self, request, inInfo, outInfo): |
408 | 413 | @smproxy.filter() |
409 | 414 | @smproperty.input(name="Input") |
410 | 415 | @smdomain.datatype( |
411 | | - dataTypes=["vtkPolyData", "vtkUnstructuredGrid"], composite_data_supported=False |
| 416 | + dataTypes=["vtkPolyData"], composite_data_supported=False |
412 | 417 | ) |
413 | 418 | @smproperty.xml( |
414 | 419 | """ |
415 | | - <IntVectorProperty name="Center Meridian" |
416 | | - command="SetCentralMeridian" |
417 | | - number_of_elements="1" |
418 | | - default_values="0"> |
419 | | - </IntVectorProperty> |
| 420 | + <DoubleVectorProperty name="Longitude Range" |
| 421 | + command="SetLongitudeRange" |
| 422 | + number_of_elements="2" |
| 423 | + default_values="-180 180"> |
| 424 | + </DoubleVectorProperty> |
| 425 | + <DoubleVectorProperty name="Latitude Range" |
| 426 | + command="SetLatitudeRange" |
| 427 | + number_of_elements="2" |
| 428 | + default_values="-90 90"> |
| 429 | + </DoubleVectorProperty> |
420 | 430 | """ |
421 | 431 | ) |
422 | | -class EAMCenterMeridian(VTKPythonAlgorithmBase): |
| 432 | +class EAMExtract(VTKPythonAlgorithmBase): |
423 | 433 | def __init__(self): |
424 | 434 | super().__init__( |
425 | 435 | nInputPorts=1, nOutputPorts=1, outputType="vtkUnstructuredGrid" |
426 | 436 | ) |
427 | | - self.project = 0 |
428 | | - self.cmeridian = 0.0 |
| 437 | + self.longrange = [-180.0, 180.0] |
| 438 | + self.latrange = [-90.0, 90.0] |
429 | 439 |
|
430 | | - def SetCentralMeridian(self, meridian): |
431 | | - if self.cmeridian != meridian: |
432 | | - self.cmeridian = meridian |
| 440 | + def SetLongitudeRange(self, min, max): |
| 441 | + if self.longrange[0] != min or self.longrange[1] != max: |
| 442 | + self.longrange = [min, max] |
| 443 | + self.Modified() |
| 444 | + |
| 445 | + def SetLatitudeRange(self, min, max): |
| 446 | + if self.latrange[0] != min or self.latrange[1] != max: |
| 447 | + self.latrange = [min, max] |
433 | 448 | self.Modified() |
434 | 449 |
|
435 | 450 | def RequestData(self, request, inInfo, outInfo): |
436 | 451 | inData = self.GetInputData(inInfo, 0, 0) |
437 | 452 | outData = self.GetOutputData(outInfo, 0) |
438 | | - |
439 | | - if self.cmeridian == 0: |
| 453 | + if self.longrange == [-180.0, 180] and self.latrange == [-90, 90]: |
440 | 454 | outData.ShallowCopy(inData) |
441 | 455 | return 1 |
442 | 456 |
|
443 | | - split = (self.cmeridian - 180) if self.cmeridian > 0 else (self.cmeridian + 180) |
| 457 | + box = vtkPVBox() |
| 458 | + box.SetReferenceBounds( |
| 459 | + self.longrange[0], |
| 460 | + self.longrange[1], |
| 461 | + self.latrange[0], |
| 462 | + self.latrange[1], |
| 463 | + -1.0, |
| 464 | + 1.0, |
| 465 | + ) |
| 466 | + box.SetUseReferenceBounds(True) |
| 467 | + extract = vtkPVClipDataSet() |
| 468 | + extract.SetClipFunction(box) |
| 469 | + extract.InsideOutOn() |
| 470 | + extract.ExactBoxClipOn() |
| 471 | + extract.SetInputData(inData) |
| 472 | + extract.Update() |
444 | 473 |
|
445 | | - planeL = vtkPlane() |
446 | | - planeL.SetOrigin([split, 0.0, 0.0]) |
447 | | - planeL.SetNormal([-1, 0, 0]) |
448 | | - clipL = vtkTableBasedClipDataSet() |
449 | | - clipL.SetClipFunction(planeL) |
450 | | - clipL.SetInputData(inData) |
451 | | - clipL.Update() |
| 474 | + outData.ShallowCopy(extract.GetOutput()) |
| 475 | + return 1 |
452 | 476 |
|
453 | | - planeR = vtkPlane() |
454 | | - planeR.SetOrigin([split, 0.0, 0.0]) |
455 | | - planeR.SetNormal([1, 0, 0]) |
456 | | - clipR = vtkTableBasedClipDataSet() |
457 | | - clipR.SetClipFunction(planeR) |
458 | | - clipR.SetInputData(inData) |
459 | | - clipR.Update() |
460 | 477 |
|
461 | | - transFunc = vtkTransform() |
462 | | - transFunc.Translate(360, 0, 0) |
463 | | - transform = vtkTransformFilter() |
464 | | - transform.SetInputData(clipL.GetOutput()) |
465 | | - transform.SetTransform(transFunc) |
466 | | - transform.Update() |
467 | 478 |
|
468 | | - append = vtkAppendFilter() |
469 | | - append.AddInputData(clipR.GetOutput()) |
470 | | - append.AddInputData(transform.GetOutput()) |
471 | | - append.Update() |
| 479 | +@smproxy.filter() |
| 480 | +@smproperty.input(name="Input") |
| 481 | +@smproperty.xml( |
| 482 | + """ |
| 483 | + <IntVectorProperty name="Meridian" |
| 484 | + command="SetMeridian" |
| 485 | + number_of_elements="1" |
| 486 | + default_values="0"> |
| 487 | + <IntRangeDomain min="-180" max="180" name="range" /> |
| 488 | + <Documentation> |
| 489 | + Sets the central meridian. |
| 490 | + Commonly used central meridians (longitudes) (- represents West, + represents East, |
| 491 | + 0 is Greenwitch prime meridian): |
| 492 | + - 0 (Prime Meridian): Standard "Western" view. |
| 493 | + - -90/-100: Centered on North America. |
| 494 | + - 100/110: Centered on Asia. |
| 495 | + - -150/-160: Centered on the Pacific Ocean. |
| 496 | + - 20: Often used to center Europe and Africa. |
| 497 | + </Documentation> |
| 498 | + </IntVectorProperty> |
| 499 | + """ |
| 500 | +) |
| 501 | +@smdomain.datatype( |
| 502 | + dataTypes=["vtkPolyData", "vtkUnstructuredGrid"], composite_data_supported=False |
| 503 | +) |
| 504 | +class EAMCenterMeridian(VTKPythonAlgorithmBase): |
| 505 | + '''Cuts an unstructured grid and re-arranges the pieces such that |
| 506 | + the specified meridian is in the middle. Note that the mesh is |
| 507 | + specified with bounds [0, 360], but the meridian is specified in the more |
| 508 | + common bounds [-180, 180]. |
| 509 | + ''' |
| 510 | + def __init__(self): |
| 511 | + super().__init__( |
| 512 | + nInputPorts=1, nOutputPorts=1, outputType="vtkUnstructuredGrid" |
| 513 | + ) |
| 514 | + # common values: |
| 515 | + self._center_meridian = 0 |
| 516 | + self._cached_output = None |
| 517 | + |
| 518 | + def SetMeridian(self, meridian_): |
| 519 | + ''' |
| 520 | + Specifies the central meridian (longitude in the middle of the map) |
| 521 | + ''' |
| 522 | + if meridian_ < -180 or meridian_ > 180: |
| 523 | + print_error("SetMeridian called with parameter outside [-180, 180]: {}".format(meridian_)) |
| 524 | + return |
| 525 | + self._center_meridian = meridian_ |
| 526 | + self.Modified() |
472 | 527 |
|
473 | | - transFunc = vtkTransform() |
474 | | - transFunc.Translate(-(180 + split), 0, 0) |
475 | | - transform = vtkTransformFilter() |
476 | | - transform.SetInputData(append.GetOutput()) |
477 | | - transform.SetTransform(transFunc) |
478 | | - transform.Update() |
| 528 | + def GetMeridian(self): |
| 529 | + ''' |
| 530 | + Returns the central meridian |
| 531 | + ''' |
| 532 | + return self._center_meridian |
479 | 533 |
|
480 | | - outData.ShallowCopy(transform.GetOutput()) |
| 534 | + def RequestData(self, request, inInfo, outInfo): |
| 535 | + inData = self.GetInputData(inInfo, 0, 0) |
| 536 | + inPoints = inData.GetPoints() |
| 537 | + inCellArray = inData.GetCells() |
| 538 | + |
| 539 | + outData = self.GetOutputData(outInfo, 0) |
| 540 | + if self._cached_output and self._cached_output.GetMTime() > inPoints.GetMTime() and \ |
| 541 | + self._cached_output.GetMTime() > inCellArray.GetMTime(): |
| 542 | + # only scalars have been added or removed |
| 543 | + cached_cell_data = self._cached_output.GetCellData() |
| 544 | + |
| 545 | + in_cell_data = inData.GetCellData() |
| 546 | + |
| 547 | + outData.ShallowCopy(self._cached_output) |
| 548 | + out_cell_data = outData.GetCellData() |
| 549 | + |
| 550 | + out_cell_data.Initialize() |
| 551 | + for i in range(in_cell_data.GetNumberOfArrays()): |
| 552 | + in_array = in_cell_data.GetArray(i) |
| 553 | + cached_array = cached_cell_data.GetArray(in_array.GetName()) |
| 554 | + if cached_array and cached_array.GetMTime() >= in_array.GetMTime(): |
| 555 | + # this scalar has been seen before |
| 556 | + # simply add a reference in the outData |
| 557 | + out_cell_data.AddArray(in_array) |
| 558 | + else: |
| 559 | + # this scalar is new |
| 560 | + # we have to fill in the additional cells resulted from the clip |
| 561 | + out_array = in_array.NewInstance() |
| 562 | + array0 = cached_cell_data.GetArray(0) |
| 563 | + out_array.SetNumberOfComponents(array0.GetNumberOfComponents()) |
| 564 | + out_array.SetNumberOfTuples(array0.GetNumberOfTuples()) |
| 565 | + out_array.SetName(in_array.GetName()) |
| 566 | + out_cell_data.AddArray(out_array) |
| 567 | + outData.cell_data[out_array.GetName()] = inData.cell_data[i][self._cached_output.cell_data['PedigreeIds']] |
| 568 | + else: |
| 569 | + generate_ids = vtkGenerateIds() |
| 570 | + generate_ids.SetInputData(inData) |
| 571 | + generate_ids.PointIdsOff() |
| 572 | + generate_ids.SetCellIdsArrayName("PedigreeIds") |
| 573 | + |
| 574 | + cut_meridian = self._center_meridian + 180 |
| 575 | + plane = vtkPlane() |
| 576 | + plane.SetOrigin([cut_meridian, 0.0, 0.0]) |
| 577 | + plane.SetNormal([-1, 0, 0]) |
| 578 | + # vtkClipPolyData hangs |
| 579 | + clipL = vtkTableBasedClipDataSet() |
| 580 | + clipL.SetClipFunction(plane) |
| 581 | + clipL.SetInputConnection(generate_ids.GetOutputPort()) |
| 582 | + clipL.Update() |
| 583 | + |
| 584 | + plane.SetNormal([1, 0, 0]) |
| 585 | + clipR = vtkTableBasedClipDataSet() |
| 586 | + clipR.SetClipFunction(plane) |
| 587 | + clipR.SetInputConnection(generate_ids.GetOutputPort()) |
| 588 | + clipR.Update() |
| 589 | + |
| 590 | + transFunc = vtkTransform() |
| 591 | + transFunc.Translate(-360, 0, 0) |
| 592 | + transform = vtkTransformFilter() |
| 593 | + transform.SetInputData(clipR.GetOutput()) |
| 594 | + transform.SetTransform(transFunc) |
| 595 | + transform.Update() |
| 596 | + |
| 597 | + append = vtkAppendFilter() |
| 598 | + append.AddInputData(clipL.GetOutput()) |
| 599 | + append.AddInputData(transform.GetOutput()) |
| 600 | + append.Update() |
| 601 | + outData.ShallowCopy(append.GetOutput()) |
| 602 | + self._cached_output = outData.NewInstance() |
| 603 | + self._cached_output.ShallowCopy(outData) |
481 | 604 | return 1 |
0 commit comments