#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
PlaneSlicer.py
平面スライス処理
"""
from __future__ import print_function
import Manyo
import Manyo.MLF as mm
import time

#########################################
def mvec(values):
    """
    タプルデータをManyo のDoubleVectorに変換
    @param  values 実数のタプルデータ
    @retval Manyo Doblu Vector
    """
    vec = Manyo.MakeDoubleVector(len(values))
    i = 0
    for value in values:
        vec[i] = value
        i += 1
    return vec

#######################################
#  PlaneSlicer
#######################################
class PlaneSlicer(object) :
    """
    ElementContainerArray または Matrix の平面切り取り
    """
    #########################################
    def __init__(self,data = None):
        """
        コンストラクタ
        @param  data  エレメントコンテナアレイまたはマトリックスのポインタ
        @retval 無し
        """
        # データが指定されているか
        if data == None:
            self._pls = mm.MlfMatrixSlicer()
        else:
            self._pls = mm.MlfMatrixSlicer(data)
        self._org = None
        self._x = None
        self._y = None
        self._sliceCondition = None
        self._lines = Manyo.ElementContainerArray()
        self._start = None
        self._end = None
        self._lineCondition = None

    #########################################
    def SetAxes(self, keyX, keyY, keyZ):
        """
        3軸を、キーによって指定
        @param  keyX (string) X軸のキー
        @param  keyY (string) Y軸のキー
        @param  keyZ (string) Z軸のキー
        @retval True: OK, False : NG
        """
        if keyX != None and not isinstance(keyX, str):
            print("keyX must be string.")
            return False
        if keyY != None and not isinstance(keyY, str):
            print("keyY must be string.")
            return False
        if keyY != None and not isinstance(keyZ, str):
            print("keyZ must be string.")
            return False
        return self._pls.SetAxes(keyX, keyY, keyZ)

    #########################################
    def IsValid(self):
        """
        平面スライスが可能か
        @param  無し
        @retval True: Valid, False : Invalid
        """
        return self._pls.IsValid()

    #########################################
    def SetPlaneKeys(self, xkey, ykey):
        """
        平面のX軸とY軸ののKey文字列設定
        @param  xkey (string) 平面のX軸を示すキー
        @param  ykey (string) 平面のY軸を示すキー
        @retval 無し
        """
        if xkey != None and not isinstance(xkey, str):
            print("xkey is not string. Unable to set.")
            return
        if ykey != None and not isinstance(ykey, str):
            print("ykey is not string. Unable to set.")
            return
        self._pls.SetPlaneKeys(xkey, ykey)

    #########################################
    def SetPlane(self, plane):
        """
        平面の設定
        @param  plane (ElementContainerArray*) 平面
        @retval 無し
        """
        self._org = None
        self._x = None
        self._y = None
        self._sliceCondition = None
        self._lines = Manyo.ElementContainerArray()
        self._start = None
        self._end = None
        self._lineCondition = None
        return self._pls.SetPlane(plane)

    #########################################
    def GetPlane(self, org, x, y, xbin, ybin,Xrange,Yrange, thickness):
        """
        平面スライス
        @param  org (float,float,float) 原点を示す座標
        @param  x (float,float,float) X軸上の点の座標
        @param  y (float,float,float) Y軸上の点の座標
        @param  xbin (float) X軸のbin幅
        @param  ybin (float) Y軸のbin幅
        @param  rangex (float,float) X軸の範囲
        @param  rangey (float,float) Y軸の範囲
        @param  thickness (float) 平面の厚さ
        @retval ElementContainerArray
        """
        # 条件を保存
        self._org = [org[0],org[1],org[2]]
        self._x = [x[0],x[1],x[2]]
        self._y = [y[0],y[1],y[2]]
        self._sliceCondition = (xbin, ybin,Xrange,Yrange, thickness)
        # ラインは初期化
        del self._lines
        self._lines = Manyo.ElementContainerArray()
        self._start = None
        self._end = None
        self._lineCondition = None
        #t1 = time.time()
        # 平面の切り取り
        plane = self._pls.GetPlane(mvec(org), mvec(x), mvec(y), xbin, ybin, \
                                  mvec(Xrange), mvec(Yrange), thickness)
        #t2 = time.time()
        #print "Slice time(s): ", (t2-t1)
        return plane

    #########################################
    def GetNextPlane(self, xdiff, ydiff, zdiff):
        """
        次の平面をスライス
        @param  xdiff (float) 原点のシフト量(x)
        @param  ydiff (float) 原点のシフト量(y)
        @param  zdiff (float) 原点のシフト量(z)
        @retval ElementContainerArray
        """
        # 先に GetPlane が実行されているか
        if self._org == None:
            print("Execute 'GetPlane' before. ")
            return Manyo.ElementContainerArray()

        xbin, ybin,Xrange,Yrange, thickness = self._sliceCondition
        # 原点のシフト
        self._org[0] += xdiff
        self._org[1] += ydiff
        self._org[2] += zdiff
        # X軸上の点のシフト
        self._x[0] += xdiff
        self._x[1] += ydiff
        self._x[2] += zdiff
        # Y軸上の点のシフト
        self._y[0] += xdiff
        self._y[1] += ydiff
        self._y[2] += zdiff

        # シフト後の平面の切り取り
        return self._pls.GetPlane(mvec(self._org), mvec(self._x), mvec(self._y), xbin, ybin, \
                                  mvec(Xrange), mvec(Yrange), thickness)


    #########################################
    def SetLineKeys(self, xkey, ykey):
        """
        線分のX軸とY軸ののKey文字列設定
        @param  xkey (string) 平面のX軸を示すキー
        @param  ykey (string) 平面のY軸を示すキー
        @retval 無し
        """
        if xkey != None and not isinstance(xkey, str):
            print("xkey is not string. Unable to set.")
            return
        if ykey != None and not isinstance(ykey, str):
            print("ykey is not string. Unable to set.")
            return
        self._pls.SetLineKeys(xkey, ykey)

    #########################################
    def GetLine(self, start, end, lbin, width):
        """
        直線を切り出す
        @param  start (float, float) 始点(x,y)
        @param  end (float,float) 終点(x,y)
        @param  lbin (float) 刻み
        @param  width (float) 幅
        @retval ElementContainerArray
        """
        self._start = [start[0], start[1]]
        self._end = [end[0], end[1]]
        self._lineCondition = (lbin, width)
        line = self._pls.GetLine(mvec(start), mvec(end), lbin, width)
        # ラインが取得できていれば
        if line.PutSize() > 0:
            self._lines.Add(line)
        else:
            print("Failed to get line.")
        return line


    #########################################
    def GetLineInfo(self):
        """
        直線情報取得
        @param  無し
        @retval (start, end, (bin, width) )
        """
        return (self._start,self._end,self._lineCondition)

    #########################################
    def GetNextLine(self, xdiff, ydiff):
        """
        次の線分を取得
        @param  xdiff (float) 線分のシフト量(x)
        @param  ydiff (float) 線分のシフト量(y)
        @retval ElementContainer
        """
        # 先に GetPlane が実行されているか
        if self._start == None:
            print("Execute 'GetLine' before. ")
            return Manyo.ElementContainer()
        lbin, width = self._lineCondition
        # 始点のシフト
        self._start[0] += xdiff
        self._start[1] += ydiff
        # 終点のシフト
        self._end[0] += xdiff
        self._end[1] += ydiff
        line = self._pls.GetLine(mvec(self._start), mvec(self._end), lbin, width)
        # ラインが取得できていれば
        if line.PutSize() > 0:
            self._lines.Add(line)
        else:
            print("Failed to get line.")
        return line

    #########################################
    def ClearLines(self):
        """
        線分をクリア
        @param  無し
        @retval 無し
        """
        self._lines = Manyo.ElementContainerArray()

    #########################################
    def GetLines(self):
        """
        線分の集合を取得
        @param  無し
        @retval ElementContainerArray
        """
        return self._lines

