class_docstr: Pen calculating area, center of mass, variance and
  standard-deviation, covariance and correlation, and slant,
  of glyph shapes, using the control polygon only.
  
  Note that if the glyph shape is self-intersecting, the values
  are not correct (but well-defined). Moreover, area will be
  negative if contour directions are clockwise.
class_docstr_tok: ["Pen","calculating","area",",","center","of","mass",",","variance","and","standard-deviation",",","covariance","and","correlation",",","and","slant",",","of","glyph","shapes",",","using","the","control","polygon","only",".","Note","that","if","the","glyph","shape","is","self-intersecting",",","the","values","are","not","correct","(","but","well-defined",")",".","Moreover",",","area","will","be","negative","if","contour","directions","are","clockwise","."]
code: def _update(self):
      nodes = self._nodes
      n = len(nodes)
  
      # Triangle formula
      self.area = (
          sum(
              (p0.real * p1.imag - p1.real * p0.imag)
              for p0, p1 in zip(nodes, nodes[1:] + nodes[:1])
          )
          / 2
      )
  
      # Center of mass
      # https://en.wikipedia.org/wiki/Center_of_mass#A_system_of_particles
      sumNodes = sum(nodes)
      self.meanX = meanX = sumNodes.real / n
      self.meanY = meanY = sumNodes.imag / n
  
      if n > 1:
          # Var(X) = (sum[X^2] - sum[X]^2 / n) / (n - 1)
          # https://www.statisticshowto.com/probability-and-statistics/descriptive-statistics/sample-variance/
          self.varianceX = varianceX = (
              sum(p.real * p.real for p in nodes)
              - (sumNodes.real * sumNodes.real) / n
          ) / (n - 1)
          self.varianceY = varianceY = (
              sum(p.imag * p.imag for p in nodes)
              - (sumNodes.imag * sumNodes.imag) / n
          ) / (n - 1)
  
          # Covariance(X,Y) = (sum[X.Y] - sum[X].sum[Y] / n) / (n - 1)
          self.covariance = covariance = (
              sum(p.real * p.imag for p in nodes)
              - (sumNodes.real * sumNodes.imag) / n
          ) / (n - 1)
      else:
          self.varianceX = varianceX = 0
          self.varianceY = varianceY = 0
          self.covariance = covariance = 0
  
      StatisticsBase._update(self)
  
imports: from math import sqrt, degrees, atan
  from fontTools.pens.basePen import BasePen, OpenContourError
  from fontTools.pens.momentsPen import MomentsPen
label_desc: Use image node_id 8 for calling the StatisticsControlPen obj's underlying member method code with example usage: obj._update() without return types