# -*- coding: utf-8 -*-

###############################################
#
#	SketcherClipView
#
# This macro creates a temporary cross section at the
# sketch plane in order to 'look into' an object when you
# want to create a feature on the inside (i.e. create a revolved
# groove on the inner side of a tube).
#
# The macro creates a clipping plane at the sketch plane and
# activates it. Running the macro again deletes the clipping plane.
#
# If you map the macro to F7 it behaves almost exactly like
# in Autodesk Inventor, from which I got the inspiration.
#
# (c) Ricardo Beck
#################################################

__Name__ = 'Sketcher Clip View'
__Comment__ = 'Creates a temporary clipping plane at the support plane of the sketch'
__License__ = ''
__Web__ = 'https://forum.freecadweb.org/viewtopic.php?t=26608'
__Wiki__ = ''
__Icon__ = 'SketcherClipView.svg'
__Help__ = 'Launch while editing a sketch'
__Author__ = 'Ricardo Beck, galou_breizh'
__Version__ = '1.1.0'
__Date__ = '2018-05-29'
__Status__ = 'Beta'
__Requires__ = 'FreeCAD >= v0.17'
__Files__ = 'SketcherClipView.svg'

from pivy import coin

import freecad as fc
import FreeCAD as app
import FreeCADGui as gui
from PySide import QtCore


def in_edit_mode():
    """Return True if the Sketcher is in edit mode

    This is done by checking whether ActiveSketch is defined and
    ActiveSketch.ViewObject.TempoVis is not None.
    """
    in_edit_mode = False
    try:
        in_edit_mode = (ActiveSketch.ViewObject.TempoVis is not None)
    except NameError:
        pass
    return in_edit_mode


def check_leave_edit():
    if not in_edit_mode():
        clean()


def clean():
    if hasattr(fc, 'SketcherClipView_clip_plane'):
        gui.activeDocument().ActiveView.getSceneGraph().removeChild(fc.SketcherClipView_clip_plane)
        del fc.SketcherClipView_clip_plane
        del fc.SketcherClipView_timer


def main():
    # Check if there is a temporary clipping plane from a previous run of the
    # macro.
    if hasattr(fc, 'SketcherClipView_clip_plane'):
        # Clipping plane found, remove from scenegraph and delete the object.
        clean()
        return

    if not in_edit_mode():
        return

    # No clipping plane found, create one at the sketch base.

    # Get the placement information of the active sketch.
    try:
        mat = ActiveSketch.getGlobalPlacement()
    except NameError:
        # ActiveSketch undefined (i.e. not in sketch editing mode).
        return
    point = mat.Base
    normal = mat.Rotation.multVec(app.Vector(0, 0, 1))

    # Create coin3d vectors of the sketch position.
    coin_normal_vector = coin.SbVec3f(normal.x, normal.y, normal.z)
    coin_normal_vector.negate()
    coin_base_point = coin.SbVec3f(point.x, point.y, point.z)

    # Offset of the clipping plane so the sketch elements (lines, etc) are not cut off.
    sketch_offset_factor = -0.02

    coin_normal_vector_normalized = coin.SbVec3f(coin_normal_vector)
    coin_normal_vector_normalized.normalize()

    # Offset the clipping plane base by a fraction of the (normalized) normal vector.
    coin_base_point += (coin_normal_vector_normalized * sketch_offset_factor)

    # Create the clipping plane at the calculated position.
    fc.SketcherClipView_clip_plane = coin.SoClipPlane()
    fc.SketcherClipView_clip_plane.plane.setValue(coin.SbPlane(coin_normal_vector,coin_base_point))
    gui.activeDocument().ActiveView.getSceneGraph().insertChild(fc.SketcherClipView_clip_plane, 0)

    # Switch clipping plane on.
    fc.SketcherClipView_clip_plane.on.setValue(True)

    fc.SketcherClipView_timer = QtCore.QTimer()
    fc.SketcherClipView_timer.timeout.connect(check_leave_edit)
    fc.SketcherClipView_timer.start(100)  # Pool every 100 ms.

if __name__ == '__main__':
    main()
