parameters: (self, x, y)
docstring: paint with a brush that is circular (or optionally spherical) in XY space
       (could be stretched or rotate when transformed to IJK)
       - make sure to hit every pixel in IJK space
       - apply the threshold if selected
docstring_summary: paint with a brush that is circular (or optionally spherical) in XY space
       (could be stretched or rotate when transformed to IJK)
       - make sure to hit every pixel in IJK space
       - apply the threshold if selected
docstring_tokens: paint with a brush that is circular ( or optionally spherical ) in XY space ( could be stretched or rotate when transformed to IJK ) - make sure to hit every pixel in IJK space - apply the threshold if selected
function: def paintBrush(self, x, y):
      """
      paint with a brush that is circular (or optionally spherical) in XY space
       (could be stretched or rotate when transformed to IJK)
       - make sure to hit every pixel in IJK space
       - apply the threshold if selected
      """
  
      sliceLogic = self.sliceWidget.sliceLogic()
      sliceNode = sliceLogic.GetSliceNode()
      labelLogic = sliceLogic.GetLabelLayer()
      labelNode = labelLogic.GetVolumeNode()
      labelImage = labelNode.GetImageData()
      backgroundLogic = sliceLogic.GetBackgroundLayer()
      backgroundNode = backgroundLogic.GetVolumeNode()
      backgroundImage = backgroundNode.GetImageData()
  
      if not labelNode:
        # if there's no label, we can't paint
        return
  
      #
      # get the brush bounding box in ijk coordinates
      # - get the xy bounds
      # - transform to ijk
      # - clamp the bounds to the dimensions of the label image
      #
      bounds = self.brush.GetPoints().GetBounds()
      left = x + bounds[0]
      right = x + bounds[1]
      bottom = y + bounds[2]
      top = y + bounds[3]
  
      xyToIJK = labelLogic.GetXYToIJKTransform()
      tlIJK = xyToIJK.TransformDoublePoint( (left, top, 0) )
      trIJK = xyToIJK.TransformDoublePoint( (right, top, 0) )
      blIJK = xyToIJK.TransformDoublePoint( (left, bottom, 0) )
      brIJK = xyToIJK.TransformDoublePoint( (right, bottom, 0) )
  
      dims = labelImage.GetDimensions()
  
      # clamp the top, bottom, left, right to the
      # valid dimensions of the label image
      tl = [0,0,0]
      tr = [0,0,0]
      bl = [0,0,0]
      br = [0,0,0]
      for i in range(3):
        tl[i] = int(round(tlIJK[i]))
        if tl[i] < 0:
          tl[i] = 0
        if tl[i] >= dims[i]:
          tl[i] = dims[i] - 1
        tr[i] = int(round(trIJK[i]))
        if tr[i] < 0:
          tr[i] = 0
        if tr[i] >= dims[i]:
          tr[i] = dims[i] - 1
        bl[i] = int(round(blIJK[i]))
        if bl[i] < 0:
          bl[i] = 0
        if bl[i] >= dims[i]:
          bl[i] = dims[i] - 1
        br[i] = int(round(brIJK[i]))
        if br[i] < 0:
          br[i] = 0
        if br[i] >= dims[i]:
          br[i] = dims[i] - 1
  
      # If the region is smaller than a pixel then paint it using paintPixel mode,
      # to make sure at least one pixel is filled on each click
      maxRowDelta = 0
      maxColumnDelta = 0
      for i in range(3):
        d = abs(tr[i] - tl[i])
        if d > maxColumnDelta:
          maxColumnDelta = d
        d = abs(br[i] - bl[i])
        if d > maxColumnDelta:
          maxColumnDelta = d
        d = abs(bl[i] - tl[i])
        if d > maxRowDelta:
          maxRowDelta = d
        d = abs(br[i] - tr[i])
        if d > maxRowDelta:
          maxRowDelta = d
      if maxRowDelta<=1 or maxColumnDelta<=1 :
        self.paintPixel(x,y)
        return
  
      #
      # get the layers and nodes
      # and ijk to ras matrices including transforms
      #
      backgroundIJKToRAS = self.logic.getIJKToRASMatrix(backgroundNode)
      labelIJKToRAS = self.logic.getIJKToRASMatrix(labelNode)
  
      xyToRAS = sliceNode.GetXYToRAS()
      brushCenter = xyToRAS.MultiplyPoint( (x, y, 0, 1) )[:3]
  
      brushRadius = self.radius
      bSphere = self.sphere
  
      parameterNode = EditUtil.getParameterNode()
      paintLabel = int(parameterNode.GetParameter("label"))
      paintOver = int(parameterNode.GetParameter("LabelEffect,paintOver"))
      paintThreshold = int(parameterNode.GetParameter("LabelEffect,paintThreshold"))
      paintThresholdMin = float(
          parameterNode.GetParameter("LabelEffect,paintThresholdMin"))
      paintThresholdMax = float(
          parameterNode.GetParameter("LabelEffect,paintThresholdMax"))
  
      #
      # set up the painter class and let 'r rip!
      #
      if not hasattr(self,"painter"):
        self.painter = slicer.vtkImageSlicePaint()
  
      self.painter.SetBackgroundImage(backgroundImage)
      self.painter.SetBackgroundIJKToWorld(backgroundIJKToRAS)
      self.painter.SetWorkingImage(labelImage)
      self.painter.SetWorkingIJKToWorld(labelIJKToRAS)
      self.painter.SetTopLeft( tl[0], tl[1], tl[2] )
      self.painter.SetTopRight( tr[0], tr[1], tr[2] )
      self.painter.SetBottomLeft( bl[0], bl[1], bl[2] )
      self.painter.SetBottomRight( br[0], br[1], br[2] )
      self.painter.SetBrushCenter( brushCenter[0], brushCenter[1], brushCenter[2] )
      self.painter.SetBrushRadius( brushRadius )
      self.painter.SetPaintLabel(paintLabel)
      self.painter.SetPaintOver(paintOver)
      self.painter.SetThresholdPaint(paintThreshold)
      self.painter.SetThresholdPaintRange(paintThresholdMin, paintThresholdMax)
  
      if bSphere:  # fill volume of a sphere rather than a circle on the currently displayed image slice
          # Algorithm:
          ###########################
          # Assume brushRadius is in mm
          # Estimate zVoxelSize
          # Compute number of slices spanned by sphere, that are still within the volume
          # For each spanned slice
          #    reposition the brushCenter using xy(z)ToRAS transform: i.e. canvas to patient world coordinates
          #    resize the radius: brushRadiusOffset=sqrt(brushRadius*brushRadius - zOffset_mm*zOffset_mm)
          #    invoke Paint()
          # Finally paint on the center slice, leaving the gui on the center slice being most visibly edited
          #------------------
          # Estimate zVoxelSize_mm
          brushCenter1 = xyToRAS.MultiplyPoint( (x, y, 0, 1) )[:3]
          brushCenter2 = xyToRAS.MultiplyPoint( (x, y, 100, 1) )[:3]
          dx1=brushCenter1[0]-brushCenter2[0]
          dx2=brushCenter1[1]-brushCenter2[1]
          dx3=brushCenter1[2]-brushCenter2[2]
          distanceSpannedBy100Slices = sqrt(dx1*dx1+dx2*dx2+dx3*dx3)  # compute L2 norm
          if distanceSpannedBy100Slices==0:
              zVoxelSize_mm=1
          else:
              zVoxelSize_mm = int(distanceSpannedBy100Slices / 100)
          # --
          # Compute number of slices spanned by sphere
          nNumSlicesInEachDirection=int(brushRadius / zVoxelSize_mm);
          nNumSlicesInEachDirection=nNumSlicesInEachDirection-1
          sliceOffsetArray=numpy.concatenate((-1*numpy.arange(1,nNumSlicesInEachDirection+1,),  numpy.arange(1,nNumSlicesInEachDirection+1)))
          for iSliceOffset in sliceOffsetArray:
              # x,y uses slice (canvas) coordinate system and actually has a 3rd z component (index into the slice you're looking at)
              # hence xyToRAS is really performing xyzToRAS.   RAS is patient world coordinate system. Note the 1 is because the trasform uses homogeneous coordinates
              iBrushCenter = xyToRAS.MultiplyPoint( (x, y, iSliceOffset, 1) )[:3]
              self.painter.SetBrushCenter( iBrushCenter[0], iBrushCenter[1], iBrushCenter[2] )
              # [ ] Need to just continue (pass this loop iteration if the brush center is not within the volume
              zOffset_mm=zVoxelSize_mm*iSliceOffset;
              brushRadiusOffset=sqrt(brushRadius*brushRadius - zOffset_mm*zOffset_mm)
              self.painter.SetBrushRadius( brushRadiusOffset )
  
              # --
              tlIJKtemp = xyToIJK.TransformDoublePoint( (left, top, iSliceOffset) )
              trIJKtemp = xyToIJK.TransformDoublePoint( (right, top, iSliceOffset) )
              blIJKtemp = xyToIJK.TransformDoublePoint( (left, bottom, iSliceOffset) )
              brIJKtemp = xyToIJK.TransformDoublePoint( (right, bottom, iSliceOffset) )
              # clamp the top, bottom, left, right to the
              # valid dimensions of the label image
              tltemp = [0,0,0]
              trtemp = [0,0,0]
              bltemp = [0,0,0]
              brtemp = [0,0,0]
              for i in range(3):
                tltemp[i] = int(round(tlIJKtemp[i]))
                if tltemp[i] < 0:
                  tltemp[i] = 0
                if tltemp[i] >= dims[i]:
                  tltemp[i] = dims[i] - 1
                trtemp[i] = int(round(trIJKtemp[i]))
                if trtemp[i] < 0:
                  trtemp[i] = 0
                if trtemp[i] > dims[i]:
                  trtemp[i] = dims[i] - 1
                bltemp[i] = int(round(blIJKtemp[i]))
                if bltemp[i] < 0:
                  bltemp[i] = 0
                if bltemp[i] > dims[i]:
                  bltemp[i] = dims[i] - 1
                brtemp[i] = int(round(brIJKtemp[i]))
                if brtemp[i] < 0:
                  brtemp[i] = 0
                if brtemp[i] > dims[i]:
                  brtemp[i] = dims[i] - 1
              self.painter.SetTopLeft( tltemp[0], tltemp[1], tltemp[2] )
              self.painter.SetTopRight( trtemp[0], trtemp[1], trtemp[2] )
              self.painter.SetBottomLeft( bltemp[0], bltemp[1], bltemp[2] )
              self.painter.SetBottomRight( brtemp[0], brtemp[1], brtemp[2] )
  
  
              self.painter.Paint()
  
  
      # paint the slice: same for circular and spherical brush modes
      self.painter.SetTopLeft( tl[0], tl[1], tl[2] )
      self.painter.SetTopRight( tr[0], tr[1], tr[2] )
      self.painter.SetBottomLeft( bl[0], bl[1], bl[2] )
      self.painter.SetBottomRight( br[0], br[1], br[2] )
      self.painter.SetBrushCenter( brushCenter[0], brushCenter[1], brushCenter[2] )
      self.painter.SetBrushRadius( brushRadius )
      self.painter.Paint()
function_tokens: def paintBrush ( self , x , y ) : sliceLogic = self . sliceWidget . sliceLogic ( ) sliceNode = sliceLogic . GetSliceNode ( ) labelLogic = sliceLogic . GetLabelLayer ( ) labelNode = labelLogic . GetVolumeNode ( ) labelImage = labelNode . GetImageData ( ) backgroundLogic = sliceLogic . GetBackgroundLayer ( ) backgroundNode = backgroundLogic . GetVolumeNode ( ) backgroundImage = backgroundNode . GetImageData ( ) if not labelNode : # if there's no label, we can't paint return # # get the brush bounding box in ijk coordinates # - get the xy bounds # - transform to ijk # - clamp the bounds to the dimensions of the label image # bounds = self . brush . GetPoints ( ) . GetBounds ( ) left = x + bounds [ 0 ] right = x + bounds [ 1 ] bottom = y + bounds [ 2 ] top = y + bounds [ 3 ] xyToIJK = labelLogic . GetXYToIJKTransform ( ) tlIJK = xyToIJK . TransformDoublePoint ( ( left , top , 0 ) ) trIJK = xyToIJK . TransformDoublePoint ( ( right , top , 0 ) ) blIJK = xyToIJK . TransformDoublePoint ( ( left , bottom , 0 ) ) brIJK = xyToIJK . TransformDoublePoint ( ( right , bottom , 0 ) ) dims = labelImage . GetDimensions ( ) # clamp the top, bottom, left, right to the # valid dimensions of the label image tl = [ 0 , 0 , 0 ] tr = [ 0 , 0 , 0 ] bl = [ 0 , 0 , 0 ] br = [ 0 , 0 , 0 ] for i in range ( 3 ) : tl [ i ] = int ( round ( tlIJK [ i ] ) ) if tl [ i ] < 0 : tl [ i ] = 0 if tl [ i ] >= dims [ i ] : tl [ i ] = dims [ i ] - 1 tr [ i ] = int ( round ( trIJK [ i ] ) ) if tr [ i ] < 0 : tr [ i ] = 0 if tr [ i ] >= dims [ i ] : tr [ i ] = dims [ i ] - 1 bl [ i ] = int ( round ( blIJK [ i ] ) ) if bl [ i ] < 0 : bl [ i ] = 0 if bl [ i ] >= dims [ i ] : bl [ i ] = dims [ i ] - 1 br [ i ] = int ( round ( brIJK [ i ] ) ) if br [ i ] < 0 : br [ i ] = 0 if br [ i ] >= dims [ i ] : br [ i ] = dims [ i ] - 1 # If the region is smaller than a pixel then paint it using paintPixel mode, # to make sure at least one pixel is filled on each click maxRowDelta = 0 maxColumnDelta = 0 for i in range ( 3 ) : d = abs ( tr [ i ] - tl [ i ] ) if d > maxColumnDelta : maxColumnDelta = d d = abs ( br [ i ] - bl [ i ] ) if d > maxColumnDelta : maxColumnDelta = d d = abs ( bl [ i ] - tl [ i ] ) if d > maxRowDelta : maxRowDelta = d d = abs ( br [ i ] - tr [ i ] ) if d > maxRowDelta : maxRowDelta = d if maxRowDelta <= 1 or maxColumnDelta <= 1 : self . paintPixel ( x , y ) return # # get the layers and nodes # and ijk to ras matrices including transforms # backgroundIJKToRAS = self . logic . getIJKToRASMatrix ( backgroundNode ) labelIJKToRAS = self . logic . getIJKToRASMatrix ( labelNode ) xyToRAS = sliceNode . GetXYToRAS ( ) brushCenter = xyToRAS . MultiplyPoint ( ( x , y , 0 , 1 ) ) [ : 3 ] brushRadius = self . radius bSphere = self . sphere parameterNode = EditUtil . getParameterNode ( ) paintLabel = int ( parameterNode . GetParameter ( "label" ) ) paintOver = int ( parameterNode . GetParameter ( "LabelEffect,paintOver" ) ) paintThreshold = int ( parameterNode . GetParameter ( "LabelEffect,paintThreshold" ) ) paintThresholdMin = float ( parameterNode . GetParameter ( "LabelEffect,paintThresholdMin" ) ) paintThresholdMax = float ( parameterNode . GetParameter ( "LabelEffect,paintThresholdMax" ) ) # # set up the painter class and let 'r rip! # if not hasattr ( self , "painter" ) : self . painter = slicer . vtkImageSlicePaint ( ) self . painter . SetBackgroundImage ( backgroundImage ) self . painter . SetBackgroundIJKToWorld ( backgroundIJKToRAS ) self . painter . SetWorkingImage ( labelImage ) self . painter . SetWorkingIJKToWorld ( labelIJKToRAS ) self . painter . SetTopLeft ( tl [ 0 ] , tl [ 1 ] , tl [ 2 ] ) self . painter . SetTopRight ( tr [ 0 ] , tr [ 1 ] , tr [ 2 ] ) self . painter . SetBottomLeft ( bl [ 0 ] , bl [ 1 ] , bl [ 2 ] ) self . painter . SetBottomRight ( br [ 0 ] , br [ 1 ] , br [ 2 ] ) self . painter . SetBrushCenter ( brushCenter [ 0 ] , brushCenter [ 1 ] , brushCenter [ 2 ] ) self . painter . SetBrushRadius ( brushRadius ) self . painter . SetPaintLabel ( paintLabel ) self . painter . SetPaintOver ( paintOver ) self . painter . SetThresholdPaint ( paintThreshold ) self . painter . SetThresholdPaintRange ( paintThresholdMin , paintThresholdMax ) if bSphere : # fill volume of a sphere rather than a circle on the currently displayed image slice # Algorithm: ########################### # Assume brushRadius is in mm # Estimate zVoxelSize # Compute number of slices spanned by sphere, that are still within the volume # For each spanned slice #    reposition the brushCenter using xy(z)ToRAS transform: i.e. canvas to patient world coordinates #    resize the radius: brushRadiusOffset=sqrt(brushRadius*brushRadius - zOffset_mm*zOffset_mm) #    invoke Paint() # Finally paint on the center slice, leaving the gui on the center slice being most visibly edited #------------------ # Estimate zVoxelSize_mm brushCenter1 = xyToRAS . MultiplyPoint ( ( x , y , 0 , 1 ) ) [ : 3 ] brushCenter2 = xyToRAS . MultiplyPoint ( ( x , y , 100 , 1 ) ) [ : 3 ] dx1 = brushCenter1 [ 0 ] - brushCenter2 [ 0 ] dx2 = brushCenter1 [ 1 ] - brushCenter2 [ 1 ] dx3 = brushCenter1 [ 2 ] - brushCenter2 [ 2 ] distanceSpannedBy100Slices = sqrt ( dx1 * dx1 + dx2 * dx2 + dx3 * dx3 ) # compute L2 norm if distanceSpannedBy100Slices == 0 : zVoxelSize_mm = 1 else : zVoxelSize_mm = int ( distanceSpannedBy100Slices / 100 ) # -- # Compute number of slices spanned by sphere nNumSlicesInEachDirection = int ( brushRadius / zVoxelSize_mm ) nNumSlicesInEachDirection = nNumSlicesInEachDirection - 1 sliceOffsetArray = numpy . concatenate ( ( - 1 * numpy . arange ( 1 , nNumSlicesInEachDirection + 1 , ) , numpy . arange ( 1 , nNumSlicesInEachDirection + 1 ) ) ) for iSliceOffset in sliceOffsetArray : # x,y uses slice (canvas) coordinate system and actually has a 3rd z component (index into the slice you're looking at) # hence xyToRAS is really performing xyzToRAS.   RAS is patient world coordinate system. Note the 1 is because the trasform uses homogeneous coordinates iBrushCenter = xyToRAS . MultiplyPoint ( ( x , y , iSliceOffset , 1 ) ) [ : 3 ] self . painter . SetBrushCenter ( iBrushCenter [ 0 ] , iBrushCenter [ 1 ] , iBrushCenter [ 2 ] ) # [ ] Need to just continue (pass this loop iteration if the brush center is not within the volume zOffset_mm = zVoxelSize_mm * iSliceOffset brushRadiusOffset = sqrt ( brushRadius * brushRadius - zOffset_mm * zOffset_mm ) self . painter . SetBrushRadius ( brushRadiusOffset ) # -- tlIJKtemp = xyToIJK . TransformDoublePoint ( ( left , top , iSliceOffset ) ) trIJKtemp = xyToIJK . TransformDoublePoint ( ( right , top , iSliceOffset ) ) blIJKtemp = xyToIJK . TransformDoublePoint ( ( left , bottom , iSliceOffset ) ) brIJKtemp = xyToIJK . TransformDoublePoint ( ( right , bottom , iSliceOffset ) ) # clamp the top, bottom, left, right to the # valid dimensions of the label image tltemp = [ 0 , 0 , 0 ] trtemp = [ 0 , 0 , 0 ] bltemp = [ 0 , 0 , 0 ] brtemp = [ 0 , 0 , 0 ] for i in range ( 3 ) : tltemp [ i ] = int ( round ( tlIJKtemp [ i ] ) ) if tltemp [ i ] < 0 : tltemp [ i ] = 0 if tltemp [ i ] >= dims [ i ] : tltemp [ i ] = dims [ i ] - 1 trtemp [ i ] = int ( round ( trIJKtemp [ i ] ) ) if trtemp [ i ] < 0 : trtemp [ i ] = 0 if trtemp [ i ] > dims [ i ] : trtemp [ i ] = dims [ i ] - 1 bltemp [ i ] = int ( round ( blIJKtemp [ i ] ) ) if bltemp [ i ] < 0 : bltemp [ i ] = 0 if bltemp [ i ] > dims [ i ] : bltemp [ i ] = dims [ i ] - 1 brtemp [ i ] = int ( round ( brIJKtemp [ i ] ) ) if brtemp [ i ] < 0 : brtemp [ i ] = 0 if brtemp [ i ] > dims [ i ] : brtemp [ i ] = dims [ i ] - 1 self . painter . SetTopLeft ( tltemp [ 0 ] , tltemp [ 1 ] , tltemp [ 2 ] ) self . painter . SetTopRight ( trtemp [ 0 ] , trtemp [ 1 ] , trtemp [ 2 ] ) self . painter . SetBottomLeft ( bltemp [ 0 ] , bltemp [ 1 ] , bltemp [ 2 ] ) self . painter . SetBottomRight ( brtemp [ 0 ] , brtemp [ 1 ] , brtemp [ 2 ] ) self . painter . Paint ( ) # paint the slice: same for circular and spherical brush modes self . painter . SetTopLeft ( tl [ 0 ] , tl [ 1 ] , tl [ 2 ] ) self . painter . SetTopRight ( tr [ 0 ] , tr [ 1 ] , tr [ 2 ] ) self . painter . SetBottomLeft ( bl [ 0 ] , bl [ 1 ] , bl [ 2 ] ) self . painter . SetBottomRight ( br [ 0 ] , br [ 1 ] , br [ 2 ] ) self . painter . SetBrushCenter ( brushCenter [ 0 ] , brushCenter [ 1 ] , brushCenter [ 2 ] ) self . painter . SetBrushRadius ( brushRadius ) self . painter . Paint ( )