        the curve along the z axis.
        '''
        from pyknotid.invariants import second_order_writhe
        gc = self.gauss_code(**kwargs)
        return second_order_writhe(gc)

    def second_order_twist(self, z):
        from pyknotid.spacecurves import complexity as com
        z = np.array(z).astype(np.float)
        assert len(z) == 3
        return com.second_order_twist(self.points, z)

    def average_crossing_number(self, samples=10, recalculate=False,
                                **kwargs):
        '''
        The (approximate) average crossing number of the space curve,
----
        single longer segment.'''

        points = self.points
        ts = np.roll(points, -1, axis=0) - points

        keep_points = np.ones(len(points), dtype=np.bool)

        ts_range = ts[:-2] if not closed else ts

        for i1, t1 in enumerate(ts_range):
            t1 /= np.sqrt(np.sum(t1**2))
            t2 = ts[(i1 + 1) % len(ts)]
            t2 /= np.sqrt(np.sum(t2**2))
----

        if not isinstance(shape, (int, float)):
            assert len(set(shape)) == 1
            shape = float(shape[0])

        # should these have +1 and -1?
        steps_mins = np.floor((b2.mins - b1.maxs) / shape).astype(np.int) + 1
        steps_maxs = np.floor((b2.maxs - b1.mins) / shape).astype(np.int)

        return steps_mins, steps_maxs

----
    line = np.vstack(line)
    loop = Knot.from_periodic_line(loop, shape)
    line = OpenKnot.from_periodic_line(line, shape)

    line_closure = (line.points[-1] - line.points[0]) / shape[0]
    line_closure = np.round(line_closure).astype(np.int)

    print('closure is', line_closure)

    b1 = BoundingBox(line.points)
    b2 = BoundingBox(loop.points)
