#author("2024-11-20T15:54:15+09:00","default:TESLA202407","TESLA202407")
#author("2024-11-20T15:54:52+09:00","default:TESLA202407","TESLA202407")
[[factory_controller_01.py]]


#code(Python){{
# -*- coding: utf-8 -*-
#
# 2024 11/20
#
import math
from tkinter import *
import tkinter.font as tkFont
import matrix
import copy
import threading
import re

import socket
import time
#import readchar
from Cube import Cube
        
class Space:
    ''' Coordiante-system: Right-handed, Matrices are column-major ones '''
    
    WIDTH = 1280.0
    HEIGHT = 960.0
    SPEED = 0.05
    EPSILON = 1.0e-8
    ZERO = EPSILON

    cxyz=[
        [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]],
        [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]],
        [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]],
        [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]],
        [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]],
        [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]],
        [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]]
    ]
    pcx=3
    pcy=3
    pcz=3

    pjxy=[[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]]
    pjyz=[[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]]
    pjzx=[[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]]

    cwxyz=[
        [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]],
        [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]],
        [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]],
        [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]],
        [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]],
        [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]],
        [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0],[0,0,0,0,0,0,0],
         [0,0,0,0,0,0,0]]
    ]

    def clear_cxyz(self):
        for i in range(7):
            for j in range(7):
                for k in range(7):
                    self.cxyz[i][j][k]=0

    def make_pjxy(self):
        for i in range(7):
            for j in range(7):
                self.pjxy[i][j]=0
                for k in range(7):
                    self.pjxy[i][j]+=self.cxyz[i][j][k]
        print("pjxy")
        for i in range(7):
            print(self.pjxy[i])
    def make_pjyz(self):
        for i in range(7):
            for j in range(7):
                self.pjyz[i][j]=0
                for k in range(7):
                    self.pjyz[i][j]+=self.cxyz[k][i][j]
        print("pjyz")
        for i in range(7):
            print(self.pjyz[i])
    def make_pjzx(self):
        for i in range(7):
            for j in range(7):
                self.pjzx[i][j]=0
                for k in range(7):
                    self.pjzx[i][j]+=self.cxyz[j][k][i]
        print("pjzx")
        for i in range(7):
            print(self.pjzx[i])
    def make_cxyz(self):
        self.clear_cxyz()
        for cx in self.polygons_3D:
            ccp=cx.get_cube_center()
            self.cxyz[round(ccp.x)+self.pcx][round(ccp.y)+self.pcy][round(ccp.z)+self.pcz]=1
        print("cxyz")
        for i in range(7):
            print(self.cxyz[i])
    
    def rotate_z_cw_90(self):
        #for k in range(7):
        #    for i in range(7):
        #        for j in range(7):
        #            self.cwxyz[j][6-i][k]=self.cxyz[i][j][k]
        #for i in range(7):
        #    for j in range(7):
        #        for k in range(7):
        #            self.cxyz[i][j][k]=self.cwxyz[i][j][k]
        for cx in self.polygons_3D:
            ccp=cx.get_cube_center()
            cx.rotate(0.0,0.0,90.0)
            cx.moveTo(ccp.y,-ccp.x,ccp.z) 
        self.update(self.polygons_3D)
    def rotate_x_cw_90(self):
        #for k in range(7):
        #    for i in range(7):
        #        for j in range(7):
        #            self.cwxyz[k][j][6-i]=self.cxyz[k][i][j]
        #for i in range(7):
        #    for j in range(7):
        #        for k in range(7):
        #            self.cxyz[i][j][k]=self.cwxyz[i][j][k]
        for cx in self.polygons_3D:
            ccp=cx.get_cube_center()
            cx.rotate(90.0,0.0,0.0)
            cx.moveTo(ccp.x,ccp.z,-ccp.y) 
        self.update(self.polygons_3D)
    def rotate_y_cw_90(self):
        #for k in range(7):
        #    for i in range(7):
        #        for j in range(7):
        #            self.cwxyz[6-i][k][j]=self.cxyz[j][k][i]
        #for i in range(7):
        #    for j in range(7):
        #        for k in range(7):
        #            self.cxyz[i][j][k]=self.cwxyz[i][j][k]
        for cx in self.polygons_3D:
            ccp=cx.get_cube_center()
            cx.rotate(0.0,90.0,0.0)
            cx.moveTo(-ccp.z,ccp.y,ccp.x) 
        self.update(self.polygons_3D)
    def max_width(self):
        max_width=-10.0
        for cx in self.polygons_3D:
            ccp=cx.get_cube_center()
            if ccp.x>max_width:
                max_width=ccp.x
        return max_width
    def min_width(self):
        min_width=10.0
        for cx in self.polygons_3D:
            ccp=cx.get_cube_center()
            if ccp.x<min_width:
                min_width=ccp.x
        return min_width
    def width(self):
        return self.max_width()-self.min_width() +1.0
    def max_height(self):
        max_height=-10.0
        for cx in self.polygons_3D:
            ccp=cx.get_cube_center()
            if ccp.y>max_height:
                max_height=ccp.y
        return max_height
    def min_height(self):
        min_height=10.0
        for cx in self.polygons_3D:
            ccp=cx.get_cube_center()
            if ccp.y<min_height:
                min_height=ccp.y
        return min_height
    def height(self):
        return self.max_height()-self.min_height() +1.0
    def max_depth(self):
        max_depth=-10.0
        for cx in self.polygons_3D:
            ccp=cx.get_cube_center()
            if ccp.z>max_depth:
                max_depth=ccp.z
        return max_depth
    def min_depth(self):
        min_depth=10.0
        for cx in self.polygons_3D:
            ccp=cx.get_cube_center()
            if ccp.z<min_depth:
                min_depth=ccp.z
        return min_depth
    def depth(self):
        return self.max_depth()-self.min_depth() +1.0
    def move_and_rotate_for_factory(self):
        wx=round(self.width())
        if wx<0.0:
            print("no tesla dice.")
            return
        hx=round(self.height())
        if hx>wx:
            self.rotate_z_cw_90()
        wx=round(self.width())
        hx=round(self.height())
        dx=round(self.depth())
        if hx>dx:
            self.rotate_x_cw_90()
        wx=round(self.width())
        hx=round(self.height())
        dx=round(self.depth())
        if dx>wx:
            self.rotate_y_cw_90()
        wx=round(self.width())
        hx=round(self.height())
        dx=round(self.depth())
        if self.there_is_over_hang():
            self.rotate_x_cw_90()
            self.rotate_x_cw_90()
        wx=round(self.width())
        hx=round(self.height())
        dx=round(self.depth())
        if self.there_is_space_at_the_first_corner():
            if hx<=1.01:
                self.rotate_x_cw_90()
                self.rotate_x_cw_90()
            else:
                self.rotate_y_cw_90()
                self.rotate_y_cw_90()

    def min_x(self):
        min_x=10.0
        for cx in self.polygons_3D:
            ccp=cx.get_cube_center()
            if ccp.x<min_x:
                min_x=ccp.x
        return min_x
    def min_y(self):
        min_y=10.0
        for cx in self.polygons_3D:
            ccp=cx.get_cube_center()
            if ccp.y<min_y:
                min_y=ccp.y
        return min_y 
    def there_is_over_hang(self):
        self.make_cxyz()
        imin_y=round(self.min_y())
        for i in range(7):
            for j in range(7):
                if self.cxyz[i][imin_y][j]==0:
                    if imin_y<6:
                        if self.cxyz[i][imin_y+1][j]==1:
                            return True
    def there_is_space_at_the_first_corner(self):
        self.make_cxyz()
        imin_y=round(self.min_y())
        imin_x=6
        imin_z=6
        for i in range(7):
            for j in range(7):
                if self.cxyz[i][imin_y][j]==1:
                    if i<imin_x:
                        imin_x=i
                    if j<imin_z:
                        imin_z=j
        fc=self.cxyz[imin_x][imin_y][imin_z]
        return fc==0
    
    #ダイスの回転
    #    org: top red, forward green, left yellow, right black, back blue, bottom white
    #
    #top red の場合
    #  forward green : 回転無し。
    #          yellow : 右回転 3回
    #          blue : 右回転2回
    #          black : 右回転1回
    #
    #top white の場合
    #  縦回転: 2回
    #   forward green : 右回転2回
    #           yellow : 右回転 1回
    #           blue : 回転無し
    #           black : 右回転3回
    #
    #top blue の場合
    #  縦回転: 1回
    #  forward red : 回転なし
    #          yellow : 右回転 3回
    #          white : 右回転2回
    #          black : 右回転1回
    #
    #top yellow の場合
    #  右回転1回
    #  縦回転: 1回
    #   forward red : 回転なし
    #          blue : 右回転1回
    #          white : 右回転2回
    #          green : 右回転3回
    #
    # top green の場合
    #  右回転 2回
    #  縦回転: 1回
    #   forward red : 回転なし
    #           yellow : 右回転1回
    #           white : 右回転2回
    #           black : 右回転3回
    #
    #top black の場合
    #  右回転 3回
    #  縦回転: 1回
    #   forward red : 回転なし
    #           green : 右回転1回
    #           white : 右回転2回
    #           blue : 右回転3回
    def generate_rotation_procedure(self,cube):
        top_face_id=cube.get_top_face()
        top_face_color=cube.cls[top_face_id]
        front_face_id=cube.get_front_face()
        front_face_color=cube.cls[front_face_id]
        if top_face_color=='red':
            #top red の場合
            #  forward black : 回転無し。
            #          green : 右回転 3回
            #          yellow : 右回転2回
            #          blue : 右回転1回
            if front_face_color=='green':
                rotation_proc='self.place_at_the_rotation_point()\n'
                self.factory.send_message_nl('asm m self.place_at_the_rotation_point()')
                rotation_proc=rotation_proc+'self.h_rotate_acw()\n'
                #rotation_proc=rotation_proc+'self.h_rotate_cw()\nself.h_rotate_cw()\nself.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_acw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
            elif front_face_color=='yellow':
                rotation_proc='self.place_at_the_rotation_point()\n'
                self.factory.send_message_nl('asm m self.place_at_the_rotation_point()')
                rotation_proc=rotation_proc+'self.h_rotate_cw()\nself.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
            elif front_face_color=='blue':
                rotation_proc='self.place_at_the_rotation_point()\n'
                self.factory.send_message_nl('asm m self.place_at_the_rotation_point()')
                rotation_proc=rotation_proc+'self.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
            elif front_face_color=='gray':
                rotation_proc='#no need to rotate\n'
                return rotation_proc
        elif top_face_color=='white':
            #top white の場合
            #  縦回転: 2回
            #   forward black : 右回転2回
            #           blue : 右回転 1回
            #           yellow : 回転無し
            #           green : 右回転3回
            rotation_proc='self.place_at_the_rotation_point()\n'
            self.factory.send_message_nl('asm m self.place_at_the_rotation_point()')
            rotation_proc=rotation_proc+'self.v_rotate_f()\nself.v_rotate_f()\n'
            self.factory.send_message_nl('asm m self.v_rotate_f()')
            self.factory.send_message_nl('asm m self.v_rotate_f()')
            if front_face_color=='green':
                #rotation_proc=rotation_proc+'self.h_rotate_cw()\nself.h_rotate_cw()\nself.h_rotate_cw()\n'
                rotation_proc=rotation_proc+'self.h_rotate_acw()\nn'
                self.factory.send_message_nl('asm m self.h_rotate_acw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc                
            elif front_face_color=='yellow':
                return rotation_proc
            elif front_face_color=='blue':
                rotation_proc=rotation_proc+'self.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
            elif front_face_color=='gray':
                rotation_proc=rotation_proc+'self.h_rotate_cw()\nself.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
        elif top_face_color=='yellow':
            #top yellow の場合
            #  縦回転: 1回
            #  forward red : 回転なし
            #           : 右回転 3回
            #          white : 右回転2回
            #          blue : 右回転1回
            rotation_proc='self.place_at_the_rotation_point()\n'
            self.factory.send_message_nl('asm m self.place_at_the_rotation_point()')
            rotation_proc=rotation_proc+'self.v_rotate_f()\n'
            self.factory.send_message_nl('asm m self.v_rotate_f()')
            if front_face_color=='green':
                rotation_proc=rotation_proc+'self.h_rotate_acw()\n'
                #rotation_proc=rotation_proc+'self.h_rotate_cw()\nself.h_rotate_cw()\nself.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_acw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
            elif front_face_color=='red':
                return rotation_proc
            elif front_face_color=='blue':
                rotation_proc=rotation_proc+'self.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
            elif front_face_color=='white':
                rotation_proc=rotation_proc+'self.h_rotate_cw()\nself.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
        elif top_face_color=='green':
            #top green の場合
            #  右回転: 1回
            #  縦回転: 1回
            #  forward red : 回転なし
            #          black : 右回転 3回
            #          white : 右回転2回
            #          blue : 右回転1回
            rotation_proc='self.place_at_the_rotation_point()\n'
            self.factory.send_message_nl('asm m self.place_at_the_rotation_point()')
            rotation_proc='self.h_rotate_cw()\n'
            self.factory.send_message_nl('asm m self.h_rotate_cw()')
            rotation_proc=rotation_proc+'self.v_rotate_f()\n'
            self.factory.send_message_nl('asm m self.v_rotate_f()')
            if front_face_color=='gray':
                rotation_proc=rotation_proc+'self.h_rotate_acw()\n'
                #rotation_proc=rotation_proc+'self.h_rotate_cw()\nself.h_rotate_cw()\nself.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_acw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
            elif front_face_color=='red':
                return rotation_proc
            elif front_face_color=='yellow':
                rotation_proc=rotation_proc+'self.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
            elif front_face_color=='white':
                rotation_proc=rotation_proc+'self.h_rotate_cw()\nself.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
        elif top_face_color=='gray':
            #top green の場合
            #  右回転: 2回
            #  縦回転: 1回
            #  forward red : 回転なし
            #          blue : 右回転 3回
            #          white : 右回転2回
            #          green : 右回転1回
            rotation_proc='self.place_at_the_rotation_point()\n'
            self.factory.send_message_nl('asm m self.place_at_the_rotation_point()')
            rotation_proc=rotation_proc+'self.h_rotate_cw()\nself.h_rotate_cw()\n'
            self.factory.send_message_nl('asm m self.h_rotate_cw()')
            self.factory.send_message_nl('asm m self.h_rotate_cw()')
            rotation_proc=rotation_proc+'self.v_rotate_f()\n'
            self.factory.send_message_nl('asm m self.v_rotate_f()')
            if front_face_color=='blue':
                rotation_proc=rotation_proc+'self.h_rotate_acw()\n'
                #rotation_proc=rotation_proc+'self.h_rotate_cw()\nself.h_rotate_cw()\nself.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_acw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
            elif front_face_color=='red':
                return rotation_proc
            elif front_face_color=='green':
                rotation_proc=rotation_proc+'self.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
            elif front_face_color=='white':
                rotation_proc=rotation_proc+'self.h_rotate_cw()\nself.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
        elif top_face_color=='blue':
            #top blue の場合
            #  left回転: 2回->1
            #  縦回転: 1回
            #  forward red : 回転なし
            #          yellow : 右回転 3回->left 1
            #          white : 右回転2回
            #          grey : 右回転1回
            rotation_proc='self.place_at_the_rotation_point()\n'
            self.factory.send_message_nl('asm m self.place_at_the_rotation_point()')
            rotation_proc=rotation_proc+'self.h_rotate_acw()\n'
            self.factory.send_message_nl('asm m self.h_rotate_acw()')
            #self.factory.send_message_nl('asm m self.h_rotate_cw()')
            rotation_proc=rotation_proc+'self.v_rotate_f()\n'
            self.factory.send_message_nl('asm m self.v_rotate_f()')
            if front_face_color=='yellow':
                rotation_proc=rotation_proc+'self.h_rotate_acw()\n'
                #rotation_proc=rotation_proc+'self.h_rotate_cw()\nself.h_rotate_cw()\nself.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_acw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                #self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
            elif front_face_color=='red':
                return rotation_proc
            elif front_face_color=='gray':
                rotation_proc=rotation_proc+'self.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
            elif front_face_color=='white':
                rotation_proc=rotation_proc+'self.h_rotate_cw()\nself.h_rotate_cw()\n'
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                self.factory.send_message_nl('asm m self.h_rotate_cw()')
                return rotation_proc
            
    dice_array_xz=[[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]]

    def init_assemble_info(self):
        for i in range(5):
            for j in range(5):
                self.dice_array_xz[i][j]=0
    
    def generate_move_procedure(self,i,j,k):
        proc=''
        if k==0:
            if i==0 and j==0:
                proc=proc+'self.place_at_0_0()'
                self.dice_array_xz[i][j]=1
            elif i==1 and j==0:
                if self.dice_array_xz[0][0]==1:
                    proc=proc+'self.place_at_1_0_nx_00()'
                    self.dice_array_xz[1][0]=1
                elif self.dice_array_xz[0][0]==0:
                    proc=proc+'self.place_at_1_0_nx_00()'
                    self.dice_array_xz[1][0]=1
            elif i==2 and j==0:
                if self.dice_array_xz[1][0]==1:
                    proc=proc+'self.place_at_2_0_nx_10()'
                    self.dice_array_xz[2][0]=1
                elif self.dice_array_xz[1][0]==0:
                    proc=proc+'self.place_at_2_0_nx_10()'
                    self.dice_array_xz[2][0]=1                   
            elif i==3 and j==0:
                if self.dice_array_xz[2][0]==1:
                    proc=proc+'self.place_at_3_0_nx_20()'
                    self.dice_array_xz[3][0]=1
                elif self.dice_array_xz[2][0]==0:
                    proc=proc+'self.place_at_3_0_nx_20()'
                    self.dice_array_xz[3][0]=1                   
            elif i==0 and j==1:
                proc=proc+'self.place_at_0_1()'
                self.dice_array_xz[i][j]=1
            elif i==1 and j==1:
                if self.dice_array_xz[0][1]==1:
                    proc=proc+'self.place_at_1_1_nx_01()'
                    self.dice_array_xz[1][1]=1
                elif self.dice_array_xz[0][1]==0:
                    proc=proc+'self.place_at_1_1_nx_01()'
                    self.dice_array_xz[1][1]=1
            elif i==2 and j==1:
                if self.dice_array_xz[1][0]==1:
                    proc=proc+'self.place_at_2_1_nx_11()'
                    self.dice_array_xz[2][1]=1
                elif self.dice_array_xz[1][0]==0:
                    proc=proc+'self.place_at_2_1_nx_11()'
                    self.dice_array_xz[2][1]=1
            elif i==3 and j==1:
                if self.dice_array_xz[2][0]==1:
                    proc=proc+'self.place_at_3_1_nx_21()'
                    self.dice_array_xz[3][1]=1
                elif self.dice_array_xz[2][0]==0:
                    proc=proc+'self.place_at_3_1_nx_21()'
                    self.dice_array_xz[3][1]=1
        elif k==1:
            if i==0 and j==0:
                proc=proc+'self.place_at_0_0_1()'
                self.dice_array_xz[i][j]=1
            elif i==1 and j==0:
                if self.dice_array_xz[0][0]==1:
                    proc=proc+'self.place_at_1_0_1_nx_00()'
                    self.dice_array_xz[1][0]=1
            elif i==2 and j==0:
                if self.dice_array_xz[1][0]==1:
                    proc=proc+'self.place_at_2_0_1_nx_10()'
                    self.dice_array_xz[2][0]=1
            elif i==3 and j==0:
                if self.dice_array_xz[2][0]==1:
                    proc=proc+'self.place_at_3_0_1_nx_20()'
                    self.dice_array_xz[3][0]=1
            elif i==0 and j==1:
                proc=proc+'self.place_at_0_1_1()'
                self.dice_array_xz[i][j]=1
            elif i==1 and j==1:
                if self.dice_array_xz[0][1]==1:
                    proc=proc+'self.place_at_1_1_1_nx_01()'
                    self.dice_array_xz[1][1]=1
            elif i==2 and j==1:
                if self.dice_array_xz[1][0]==1:
                    proc=proc+'self.place_at_2_1_1_nx_11()'
                    self.dice_array_xz[2][1]=1
            elif i==3 and j==1:
                if self.dice_array_xz[2][0]==1:
                    proc=proc+'self.place_at_3_1_1_nx_21()'
                    self.dice_array_xz[3][1]=1
        self.factory.send_message_nl('asm m '+proc)
        return proc+'\n'

    def generate_assemble_procedure(self):
        min_y=round(self.min_height())
        max_y=round(self.max_height())
        min_x=round(self.min_width())
        max_x=round(self.max_width())
        min_z=round(self.min_depth())
        max_z=round(self.max_depth())
        proc='asm start.\n'
        self.factory.send_message_nl('asm start.')
        for k in reversed(range(min_z, max_z+1)):
            for j in range(min_y, max_y+1):
                for i in range(min_x, max_x+1):
                    for cx in self.polygons_3D:
                        ccx=cx.get_cube_center()
                        iccx_x=round(ccx.x)
                        iccx_y=round(ccx.y)
                        iccx_z=round(ccx.z)
                        if i==iccx_x and j==iccx_y and k==iccx_z:
                            #print(cx.get_cube_center())
                            #print(iccx_x, iccx_y, iccx_z)
                            #print(ccx.x, ccx.y, ccx.z)
                            proc=proc+'self.get_dice_from_the_belt()\n'
                            self.factory.send_message_nl('asm m self.get_dice_from_the_belt()')
                            rproc=self.generate_rotation_procedure(cx)
                            if rproc=='#no need to rotate\n':
                                if k==1:
                                    proc=proc+'self.send_move_command(0.0,40.0)\n'
                                    self.factory.send_message_nl('asm m self.send_move_command(0.0,40.0)')
                                if k==2:
                                    proc=proc+'self.send_move_command(0.0,80.0)\n'
                                    self.factory.send_message_nl('asm m self.send_move_command(0.0,80.0)')
                            else:
                                proc=proc+rproc                                
                                proc=proc+'self.get_at_the_rotation_point()\n'
                                self.factory.send_message_nl('asm m self.get_at_the_rotation_point()')
                            mx=i-min_x
                            mz=max_z-k
                            my=j-min_y
                            mproc=self.generate_move_procedure(mx,mz,my)
                            proc=proc+mproc
        return proc

    def __init__(self):
        print("start Space.__init__")
        self.root = Tk()
        self.root.resizable(False, False)
        self.root.title('3D')
        #self.chat_client=chat_client
        left = (self.root.winfo_screenwidth() - Space.WIDTH) / 2
        top = (self.root.winfo_screenheight() - Space.HEIGHT) / 2
        self.root.geometry('%dx%d+%d+%d' % (Space.WIDTH, Space.HEIGHT, left, top))
        self.graph = Canvas(self.root, width=Space.WIDTH, height=Space.HEIGHT, background='black')
        self.graph.pack()
        
        self.walls = [matrix.Vector3D(7.0, 0.0, 0.0), matrix.Vector3D(-7.0, 0.0, 0.0), matrix.Vector3D(0.0, 7.0, 0.0), matrix.Vector3D(0.0, -7.0, 0.0), matrix.Vector3D(0.0, 0.0, 7.0), matrix.Vector3D(0.0, 0.0, -7.0)]
        self.wallsnormals = [matrix.Vector3D(-1.0, 0.0, 0.0), matrix.Vector3D(1.0, 0.0, 0.0), matrix.Vector3D(0.0, -1.0, 0.0), matrix.Vector3D(0.0, 1.0, 0.0), matrix.Vector3D(0.0, 0.0, -1.0), matrix.Vector3D(0.0, 0.0, 1.0)]
        
#################
#		self.cubenormals = []
#		for i in range(len(self.cubefaces)):
#			poly = []
#			for j in range(len(self.cubefaces[i])):
#				poly.append(self.cube[self.cubefaces[i][j]])

#			self.cubenormals.append(self.calcNormalVec(poly))
#################
        self.ang = [0.0, 0.0, 0.0] # phi(x), theta(y), psi(z) of the camera
        self.trans = [0.0, 0.0, 2.0] # translation (x, y, z) of the camera

	#The matrices (Scale, Shear, Rotate, Translate) apply to the View/Camera

	#The Scale Matrix
        self.Scale = matrix.Matrix(4, 4)
        Scalex = 1.0
        Scaley = 1.0
        Scalez = 1.0
        self.Scale[(0,0)] = Scalex
        self.Scale[(1,1)] = Scaley
        self.Scale[(2,2)] = Scalez
        
        #The Shear Matrix
        self.Shearxy = matrix.Matrix(4, 4)
        self.Shearxy[(0,2)] = 0.0
        self.Shearxy[(1,2)] = 0.0
        self.Shearxz = matrix.Matrix(4, 4)
        self.Shearxz[(0,1)] = 0.0
        self.Shearxz[(2,1)] = 0.0
        self.Shearyz = matrix.Matrix(4, 4)
        self.Shearyz[(1,0)] = 0.0
        self.Shearyz[(2,0)] = 0.0
        self.Shear = self.Shearxy*self.Shearxz*self.Shearyz
        
        #The Rotation Matrices
        self.Rotx = matrix.Matrix(4,4)
        self.Roty = matrix.Matrix(4,4)
        self.Rotz = matrix.Matrix(4,4)
        #The Translation Matrix (will contain xoffset, yoffset, zoffset)
        self.Tr = matrix.Matrix(4, 4)	
        self.Tr[(0,3)] = self.trans[0]
        self.Tr[(1,3)] = self.trans[1]
        self.Tr[(2,3)] = self.trans[2]
        
        #The Projection Matrix
        self.Proj = matrix.Matrix(4, 4)	
        #foc controls how much of the screen is viewed
        fov = 60.0 #between 30 and 90 ?
        zfar = 100.0
        znear = 0.1
        S = 1/(math.tan(math.radians(fov/2)))
        A = Space.WIDTH/Space.HEIGHT
        self.Proj[(0,0)] = S/A
        self.Proj[(1,1)] = S
        self.Proj[(2,2)] = (zfar+znear)/(znear-zfar)
        self.Proj[(3,2)] = -1.0
        self.Proj[(2,3)] = 2*(zfar*znear)/(znear-zfar)
#		self.Proj[(3,3)] = 0.0

        #ToScreen Matrix
        self.toSC = matrix.Matrix(4, 4)
        self.toSC[(0,0)] = Space.WIDTH/2
        self.toSC[(1,1)] = -Space.HEIGHT/2
        self.toSC[(0,3)] = Space.WIDTH/2
        self.toSC[(1,3)] = Space.HEIGHT/2
        
#		self.root.bind("<B1-Motion>", self.dragcallback)
#		self.root.bind("<ButtonRelease-1>", self.releasecallback)
        self.root.bind("<Key>", self.keycallback)
#		self.root.bind("<KeyRelease>", self.keyreleasecallback)
        
        self.fnt = tkFont.Font(family='Helvetica', size=12, weight='bold')
        cube1=Cube(self)
        cube1.set_name("s*")
        self.cube1=cube1
        cc1=cube1.get_cube_center()
        self.cxyz[round(cc1.x)+self.pcx][round(cc1.y)+self.pcy][round(cc1.z)+self.pcz]=1
        print(self.cxyz)
        self.polygons_3D=[cube1]
        
        self.update(self.polygons_3D)
        #self.client_start()      #comment out for debug
        
        #self.mainloop()
    
    def start_3d(self):
        self.root.mainloop()

    def clear(self):
        cube1=Cube(self)
        cube1.set_name("s*")
        self.cube1=cube1
        self.polygons_3D=[cube1]       
        self.clear_cxyz()
        cc1=cube1.get_cube_center()
        self.cxyz[round(cc1.x)+self.pcx][round(cc1.y)+self.pcy][round(cc1.z)+self.pcz]=1
        print(self.cxyz)
        self.update(self.polygons_3D)

    def lookUpCube(self,name):
        for i in range(len(self.polygons_3D)):
           cx=self.polygons_3D[i]
           if name==cx.name :
               return cx
        return None

    def update(self,polygons_3D):
        # Main simulation loop.
        self.graph.delete(ALL)
        
        self.Rotx[(1,1)] = math.cos(math.radians(360.0-self.ang[0]))
        self.Rotx[(1,2)] = -math.sin(math.radians(360.0-self.ang[0]))
        self.Rotx[(2,1)] = math.sin(math.radians(360.0-self.ang[0]))
        self.Rotx[(2,2)] = math.cos(math.radians(360.0-self.ang[0]))
        
        self.Roty[(0,0)] = math.cos(math.radians(360.0-self.ang[1]))
        self.Roty[(0,2)] = math.sin(math.radians(360.0-self.ang[1]))
        self.Roty[(2,0)] = -math.sin(math.radians(360.0-self.ang[1]))
        self.Roty[(2,2)] = math.cos(math.radians(360.0-self.ang[1]))
        
        self.Rotz[(0,0)] = math.cos(math.radians(360.0-self.ang[2]))
        self.Rotz[(0,1)] = -math.sin(math.radians(360.0-self.ang[2]))
        self.Rotz[(1,0)] = math.sin(math.radians(360.0-self.ang[2]))
        self.Rotz[(1,1)] = math.cos(math.radians(360.0-self.ang[2]))
        
        #The Rotation matrix
        self.Rot = self.Rotx*self.Roty*self.Rotz
        
        #Translation (just copying)
        self.Tr[(0,3)] = -self.trans[0]
        self.Tr[(1,3)] = -self.trans[1]
        self.Tr[(2,3)] = -self.trans[2]
        
        #The Transformation matrix
        self.Tsf = self.Scale*self.Shear*self.Rot*self.Tr
        
        #Computing the normals in __init__ and only rotating them here is the same.
#		print '+++++++++++++++'
#		for i in range(len(self.cubenormals)):
#			print self.Rot*self.cubenormals[i]
#		print '+++++++++++++++'
        
#		print '************'
        #Cube
        for ic in range(len(polygons_3D)):
            cubex=polygons_3D[ic]
            cubex.update()
            cubefaces=cubex.cubefaces
            cls=cubex.cls
            for i in range(len(cubefaces)):
                poly = [] #transformed polygon
                for j in range(len(cubefaces[0])):
                    cube=cubex.cube
                    v = cube[cubefaces[i][j]]
                    #Scale, Shear, Rotate the vertex around X axis, then around Y axis, and finally around Z axis and Translate.
                    r=self.Tsf*v
                    poly.append(r)
                n=self.calcNormalVec(poly)
                #print n
                if not self.isPolygonFrontFace(poly[0], n): #Backface culling
                    continue
                poly2d = []
                inviewingvolume = False
                for j in range(len(poly)):
                    #put the point from 3D to 2D
                    ps =self.Proj*poly[j]
                    # Puut the screenpoint in the list of transformed vertices
                    p=self.toSC*ps
                    x=int(p.x)
                    y = int(p.y)
                    poly2d.append((x, y))
                    #if only one point is in the screen (x[-1,1], y[-1,1], z[-1,1]) then draw the whole polygon
                    if (-1.0 <= ps.x <= 1.0) and (-1.0 <= ps.y <= 1.0) and (-1.0 <= ps.z <= 1.0):
                        inviewingvolume = True
                    
                    if inviewingvolume:
                        self.graph.create_polygon(*poly2d, fill=cls[i])
                        cfx=cubex.cfaces
                        xface=cfx[i]
                        xface_led=xface[0]
                        for k in range(len(xface_led)): #LED
                            v=xface_led[k]
                            r=self.Tsf*v
                            ps=self.Proj*r
                            p = self.toSC*ps
                            x, y = int(p.x), int(p.y)
                            self.graph.create_rectangle(x, y, x+3, y+3, fill="magenta")
                        v=xface[1] #photo tr
                        r=self.Tsf*v
                        ps=self.Proj*r
                        p=self.toSC*ps
                        x,y=int(p.x), int(p.y)
                        self.graph.create_rectangle(x,y, x+3, y+3, fill="cyan")
#            cfx=cubex.cfaces
#            for i in range(len(cfx)):
#                xface=cfx[i]
#                xface_led=xface[0]
#                for j in range(len(xface_led)):
#                    v=xface_led[j]
#                    r=self.Tsf*v
#                    ps=self.Proj*r
#                    p = self.toSC*ps
#                    x, y = int(p.x), int(p.y)
#                    self.graph.create_rectangle(x, y, x+3, y+3, fill="magenta")
#                v=xface[1]
#                r=self.Tsf*v
#                ps=self.Proj*r
#                p=self.toSC*ps
#                x,y=int(p.x), int(p.y)
#                self.graph.create_rectangle(x,y, x+3, y+3, fill="cyan")
	#Texts (these are in camera-CS)
        txt1 = 'xpos: '+str(self.trans[0])+' ypos: '+str(self.trans[1])+' zpos: '+str(self.trans[2])
        txt2 = 'xrot: '+str(self.ang[0])+' yrot: '+str(self.ang[1])+' zrot: '+str(self.ang[2])
        self.idTxt1 = self.graph.create_text(30,30, text=txt1, fill='white', anchor=SW, font=self.fnt)
        self.idTxt2 = self.graph.create_text(30,60, text=txt2, fill='white', anchor=SW, font=self.fnt)
        vFwd = self.getForwardVec2(self.ang[1])
        txt3 = 'Fwd: '+str(vFwd)
        self.idTxt3 = self.graph.create_text(30,90, text=txt3, fill='white', anchor=SW, font=self.fnt)
        
    def isPolygonFrontFace(self, v, n):#Clockwise?
        '''v is a vertex of the polygon, n is the normal-vector of the polygon.'''
        
        #The camera should be at (0.0, 0.0, 0.0) but that doesn't work well.
        #It seems that the camera is at (0.0, 0.0, 1.0)
        c = matrix.Vector3D(0.0, 0.0, 1.0)
        vv = v-c
        
        r = vv.dot(n)
        return r < 0.0
    
    def calcNormalVec(self, p):
        '''p is an array of vertices of the polygon/face'''
        
        v1 = p[0]-p[1]
        v2 = p[0]-p[3]
        
        v = v1.cross(v2)
        v.normalize()
        
        return v
    
    def getForwardVec1(self): #Where the camera is facing. Inverting a matrix is slow
        m = self.Rot.invert()
        
        f1 = m[(0,2)]
        f2 = m[(1,2)]
        f3 = m[(2,2)]
        
        v = matrix.Vector3D(f1, f2, f3)
        v.normalize()

		#Forward vector is really backward one, so need to be negated
        return -v
    
    def getForwardVec2(self, yrot): #Where the camera is facing.
        f1 = -math.sin(math.radians(yrot))
        f2 = 0.0
        f3 = -math.cos(math.radians(yrot))
        v = matrix.Vector3D(f1, f2, f3)
        
        return v
    
    def isCollisionPlanes(self, campos, camdir):
        num = len(self.walls)
        for i in range(num):
            iscol, dist = self.isCollisionPlane(self.walls[i], self.wallsnormals[i], campos, camdir)
            
            if iscol and dist < 0.1:
                #print( i+1, dist)
                return True
            
        return False
			
    
    def isCollisionPlane(self, p, n, campos, camdir):
        '''instead of pointonplane (p) and normalofplane (n) we could pass a polygon and calculate its normal vector here. campos is the position of the camera and camdir is the forward vector of the camera'''
        
        dist = 0.0
        
        #Dot Product Between Plane Normal And Ray Direction
        dotprod = camdir.dot(n)
        
        #Determine If Ray Parallel To Plane
        if ((dotprod < Space.ZERO) and (dotprod > -Space.ZERO)):
            return False, dist
        
        #Find Distance To Collision Point
        dist = (n.dot(p-campos))/dotprod
        
        #Test If Collision Behind Start
        if (dist < -Space.ZERO):
            return False, dist
        
        return True, dist
    
    def isCollisionCube(self, campos,polygons_3D):
        '''Checks if the camera is inside the cube (this is the bounding-box-technique (bbt) but we have a cube so we dont't need to calculate a bb) '''
        for i in range(len(polygons_3D)):
            cube=(polygons_3D[i]).cube
            cubefaces=(polygons_3D[i]).cubefaces
            
            if (campos.z >= cube[cubefaces[0][0]].z and campos.z <= cube[cubefaces[2][0]].z) and (campos.y >= cube[cubefaces[5][0]].y and campos.y <= cube[cubefaces[4][0]].y) and (campos.x >= cube[cubefaces[3][0]].x and campos.x <= cube[cubefaces[1][0]].x):
                return True
            
        return False
    
    def keycallback(self, event):
#		print event.char
#		print event.keycode
#		print event.keysym
        
        #Foward
        if event.keysym == 'Up':
            vFwd = self.getForwardVec2(self.ang[1])
            
            #Is there a collison?
            pos = matrix.Vector3D(self.trans[0]+vFwd.x*Space.SPEED, self.trans[1], self.trans[2]+vFwd.z*Space.SPEED)
            if self.isCollisionPlanes(pos, vFwd):
                return
            
            if self.isCollisionCube(pos,self.polygons_3D):
                return
            
            self.trans[0] += vFwd.x*Space.SPEED
            self.trans[2] += vFwd.z*Space.SPEED
            
        #Backward
        elif event.keysym == 'Down':
            vFwd = self.getForwardVec2(self.ang[1])
            vBck = -vFwd
            
            #Is there a collison?
            pos = matrix.Vector3D(self.trans[0]-vFwd.x*Space.SPEED, self.trans[1], self.trans[2]-vFwd.z*Space.SPEED)
            if self.isCollisionPlanes(pos, vBck):
                return
            
            if self.isCollisionCube(pos,self.polygons_3D):
                return
            
            self.trans[0] -= vFwd.x*Space.SPEED
            self.trans[2] -= vFwd.z*Space.SPEED
            
        #Turn right
        elif event.keysym == 'Right':
            self.ang[1] -= 1.5
        #Turn left
        elif event.keysym == 'Left':
            self.ang[1] += 1.5
		#Upwards
        elif event.keysym == 'u':
            #Is there a collison?
            pos = matrix.Vector3D(self.trans[0], self.trans[1]+Space.SPEED, self.trans[2])
            vUp = matrix.Vector3D(0.0, 1.0, 0.0)
            if self.isCollisionPlanes(pos, vUp):
                return
            
            if self.isCollisionCube(pos,self.polygons_3D):
                return
            
            self.trans[1] += Space.SPEED
        #Downwards
        elif event.keysym == 'd':
            #Is there a collison?
            pos = matrix.Vector3D(self.trans[0], self.trans[1]-Space.SPEED, self.trans[2])
            vDwn = matrix.Vector3D(0.0, -1.0, 0.0)
            if self.isCollisionPlanes(pos, vDwn):
                return
            
            if self.isCollisionCube(pos,self.polygons_3D):
                return
            
            self.trans[1] -= Space.SPEED
        #Quit
        elif event.keysym == 'Escape':
            self.quit()
            
        if self.ang[1] >= 360.0:
            self.ang[1] -= 360.0
        if self.ang[1] < 0.0:
            self.ang[1] += 360.0
            
        self.update(self.polygons_3D)

    def quit(self):
        self.root.quit()
        
    def client_start(self):
        """ start client """
        print("start client_start")
        handle_thread = threading.Thread(target=self.handler, daemon=True)
        self.parse("send up \"str (this s* f2d1 next s*4 f4d1)\".")
        self.parse("send up \"str (this s*4 f2d1 next s*44 f4d1)\".")
        self.update(self.polygons_3D)
        handle_thread = threading.Thread(target=self.handler, daemon=True)
        handle_thread.start()
    
    def handler(self):
        """ receive commands from terminal """
        while True:
            print("input...")
            line=input()
            self.parse(line)
            self.update(self.polygons_3D)
            
    #def clear(self):
        #cube1=Cube(self)
        #cube1.set_name("s*")
        #self.polygons_3D=[self.cube1]
        #self.clear_cxyz()
        #cc1=self.cube1.get_cube_center()
        #self.cxyz[round(cc1.x)+self.pcx][round(cc1.y)+self.pcy][round(cc1.z)+self.pcz]=1
        #self.update(self.polygons_3D)
            
    def parse(self,line):
        #self.python2fwb(">"+line)
        print("Space:parse "+line)
        p=line.find("send up ")
        if(p<0):
            return
        xl=line[(p+len("send up ")):]
        #print("xl="+xl)
        px=parser(xl)
        px.rb()
        if  not (px.key("\"")):
            return
        if not px.key("str "):
            return
        px.rb()
        if not px.key("("):
            return
        px.rb()
        if not px.key("this "):
            return
        px.rb()
        xn=[""]
        if not px.d_name(xn):
            return
        px.rb()
        dn1=xn[0]
        cn=[(0,0)]
        if not px.connect(cn):
            return
        cn1=cn[0]
        px.rb()
        if not px.key("next "):
            return
        px.rb()
        xn=[""]
        if not px.d_name(xn):
            return
        dn2=xn[0]
        px.rb()
        if not px.connect(cn):
            return
        cn2=cn[0]
        px.rb()
        if not px.key(")"):
            return
        px.rb()
        if not px.key("\""):
            return
        px.rb()
        if not px.key("."):
            return
        print("dn1="+dn1)
        cc2=None
        cube1=self.lookUpCube(dn1)
        if cube1 == None:
            print("new "+dn1)
            cube1=Cube(self)
            cube1.set_name(dn1)
            self.polygons_3D.append(cube1)
            cc1=cube1.get_cube_center()
            self.cxyz[round(cc1.x)+self.pcx][round(cc1.y)+self.pcy][round(cc1.z)+self.pcz]=1
            print(self.cxyz)
        print("dn2="+dn2)
        cube2=self.lookUpCube(dn2)
        if cube2 == None:
            print("new "+dn2)
            cube2=Cube(self)
            cube2.set_name(dn2)
            self.polygons_3D.append(cube2)
        print(cn1)
        print(cn2)
        if1=cn1[0]
        if2=cn2[0]
        id1=cn1[1]
        id2=cn2[1]
        v2=cube1.get_next_place_position(if1)
        cube2.moveTo(v2.x,v2.y,v2.z)
        cube1.rotate_nextdoor_cube_until_match_the_face(if1, cube2, if2)
        cube1.rotate_nextdoor_cube_until_match_the_direction(if1,cube2,if2,id2)
        self.update(self.polygons_3D)
        cc2=cube2.get_cube_center()
        self.cxyz[round(cc2.x)+self.pcx][round(cc2.y)+self.pcy][round(cc2.z)+self.pcz]+=1
        #print(self.cxyz)
        #self.make_pjxy()
        #self.make_pjyz()
        #self.make_pjzx()
        #print("rotate_z_cw_90")
        #self.rotate_z_cw_90()
        #self.make_pjxy()
        #self.make_pjyz()
        #self.make_pjzx()        
        #print("rotate_x_cw_90")
        #self.rotate_x_cw_90()
        #self.make_pjxy()
        #self.make_pjyz()
        #self.make_pjzx()     
    def set_factory(self,factory):
        self.factory=factory   
class parser:
#
# srs.
# ok.
# fid=2. received=ack1 face 4 dir 0 uDir 0.
# this face(2):dir(0)<-> next face(4):dir(0)
# send up "str (this s* f2d0 next s*4 f4d0)".
# fid=2, received=send up "str (this s*4 f2d0 next s*44 f4d0)".
# str (this s*4 f2d0 next s*44 f4d0)
# ok
# fid=2, received=send up "str (this s*44 f2d0 next s*444 f4d0)".
# str (this s*44 f2d0 next s*444 f4d0)".
# ok
#    
    def __init__(self,line):
        self.line=line
        print("parser init "+line)
    def alpha(self,p2a):
        #print("alpha line="+self.line)
        c=self.line[0]
        p2a[0]=c
        if(c.isalpha()):
          self.line=self.line[1:]
          return True
        return False
    def digit(self,p2i):
        #print("digit line="+self.line)
        c=self.line[0]
        if(c.isdigit()):
            p2i[0]=int(c)
            self.line=self.line[1:]
            return True
        return False
    def d_name(self,xn):
        #print("d_name line="+self.line)
        cl=['']
        if not self.alpha(cl):
            return False
        xn[0]=xn[0]+cl[0]
        if not self.key("*"):
            return False
        xn[0]=xn[0]+"*"
        dx=[0]
        while self.digit(dx):
            xn[0]=xn[0]+str(dx[0])
        return True
    
    def connect(self,tx):
        #print("connect line="+self.line)
        if not self.key("f"):
            return False
        fx=[0]
        if not self.digit(fx):
            return False
        if not self.key("d"):
            return False
        dx=[0]
        if not self.digit(dx):
            return False
        tx[0]=(fx[0],dx[0])
        return True
        
    def key(self,key):
        #print("key line="+self.line)
        #print("key="+key)
        tf=self.line.startswith(key)
        print(tf)
        if(self.line.startswith(key)):
            lk=len(key)
            self.line=self.line[lk:]
            return True
        return False
    def rb(self):
        while self.key(' '):
            continue            
      
#
#    +-----------------------------------------------------+
#    |                                             TESLA   |
#    |    +-----------+          +--------------+  DICE    |
#    |    | mbed      |          |m5atom        |          |
#    |    |           |<--UART-->|tcp_server_ex1|          |
#    |    +-----------+          +--------------+          |
#    |                            ^                        |
#    +--------------------------- | -----------------------+
#                                 |
#                                wifi.... SSID YAMA-M5ATOM-EX01
#                                 |       PASS  12345678
#                                 |
#    +--------------------------- | -----------------------+
#    |                            v                PC      |
#    |                      +------------------+           |
#    |                      |Chat_Client       |
#                           |    |             |
#                           |    v             |
#                           |   handler        |
#                           |    |             |
#                           |    v             |
#                           |   parser         |
#                           |    |             |
#                           +----|-------------+
#                                |
#                                | put
#                                v
#                           +------------------+
#                           |ex04.py           |
#                           |    |             |
#                           |    v             |
#                           |  handler         |
#                           +------------------+
#                          
# coding: utf-8
#from PIL import Image, ImageFont, ImageDraw
#import time
#import sys
#import requests
#import os
#import socket
#import threading
#from collections import deque
#import subprocess
#import copy

class Factory_Client:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    HOST = 'localhost'
    PORT = 9998
    def __init__(self):
        print("start Factory_Client.__init__")

    def start_input_thread(self):
      handle_thread2 = threading.Thread(target=self.start_input, args=(self.sock,), daemon=True)
      handle_thread2.start()
        
    # operation example
    #   1. turn on all tesla dices
    #   2. start this program, tesla_transformer_20240813_01.py
    #       Graphics window will be displayed.
    #   3. input h. for confirmation of the connection between
    #        this program and tesla dices.
    #   4. assemble the object by putting together the tesla dices.
    #   5. input the command, "srs." for start recursive structure analysis.
    #   6. the assemble object will be displayed on the graphics window.
    #   7. input the command, "rotate f."
    #   8. input the command, "generate."
    #   9. input the command, "assemble."
    def send_message_nl(self,py2x_message):
      msg=py2x_message+'\n'
      try:
          self.sock.sendall(msg.encode('utf-8',errors='replace'))
      except Exception as e:
          print("send message error: {0}".format(e))
          return
      print("send the message to the factory.")
      
    def send_message(self,py2x_message):
      msg=py2x_message
      try:
        self.sock.sendall(msg.encode('utf-8',errors='replace'))
      except Exception as e:
          print("send message error: {0}".format(e))
    def client_start(self):
      """start client"""
      try:
        self.sock.connect((self.HOST, self.PORT))
      except Exception as e:
        print("factory connect error: {0}".format(e)) 
        return
      print("factory {0}:{1} connected".format(self.HOST, self.PORT))
      handle_thread = threading.Thread(target=self.handler, args=(self.sock,), daemon=True)
      handle_thread.start()
 
    def handler(self,sock):
      """receive the message from the server and print it."""
 
      while True:
        lx=""
        while True:
          data = sock.recv(1024)
          dl=len(data)
          try:
             rd=data.decode('utf-8')
          except:
             rd='?'*dl
          for i in range(rd):
              c=rd[i]
              lx=lx+c
              if c=="." or c=="\n":
                  print("[receive] "+lx)
                  lx=""
          if c=="." or c=="\n":
              break
        print("[receive]-"+lx)
        
        if self.space!=None:
           print("factory-"+lx)
           
class Chat_Client:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    HOST = '192.168.4.1'
    PORT = 23
    def __init__(self):
        print("start Chat_Client.__init__")

    def set_space(self,space):
        self.space=space
    def start_input_thread(self):
      handle_thread2 = threading.Thread(target=self.start_input, args=(self.sock,), daemon=True)
      handle_thread2.start()

    def set_factory(self,factory):
        self.factory=factory
        
    # operation example
    #   1. turn on all tesla dices
    #   2. start this program, tesla_transformer_20240813_01.py
    #       Graphics window will be displayed.
    #   3. input the command, "connect dice."
    #   4. input the commnad, "connect factory."
    #   5. input h. for confirmation of the connection between
    #        this program and tesla dices.
    #   6. assemble the object by putting together the tesla dices.
    #   7. input the command, "srs." for start recursive structure analysis.
    #   8. the assemble object will be displayed on the graphics window.

    #   9. input the command, "rotate f."
    #   10. input the command, "generate."
    #   11. input the command, "assemble."
    def start_input(self,sock):
        print("sock=")
        print(sock)
        print("input...")
        line=""
        cx=bytearray(8)
        while True:
          try:
            line=input()
            if line=="clear.":
                self.send_message("srr.")
                self.space.clear()
            elif line.startswith("connect "):
                line=line[len("connect "):]   
                while line.startswith(" "):
                    line=line[1:]
                if line.startswith("factory."):
                    self.factory.client_start()
                elif line.startswith("dice."):
                    self.client_start()
            elif line.startswith("print "):
                line=line[len("print "):]   
                while line.startswith(" "):
                    line=line[1:]
                if line.startswith("xy."):
                    space.make_pjxy()
                elif line.startswith("yz."):
                    space.make_pjyz()
                elif line.startswith("zx."):
                    space.make_pjzx()
            elif line.startswith("rotate "):
                line=line[len("rotate "):]   
                while line.startswith(" "):
                    line=line[1:]
                if line.startswith("z."):
                    space.rotate_z_cw_90()
                elif line.startswith("y."):
                    space.rotate_y_cw_90()
                elif line.startswith("x."):
                    space.rotate_x_cw_90()
                elif line.startswith("f."):
                    space.move_and_rotate_for_factory()
            elif line.startswith("generate."):
                self.proc=space.generate_assemble_procedure()
                print("generated proc=")
                print(self.proc)
            elif line.startswith("assemble."):
                self.factory.send_message_nl(self.proc)
            elif line.startswith("send "):
                space.parse(line)
            else:
                for i in range(len(line)):
                    c=line[i]
                    #c=readchar.readkey()
                    #print(c)
                    #cx[0]=c.encode('utf-8')
                    #cx[1]=0x00
                    sock.sendall(c.encode('ascii',errors='replace'))
                    time.sleep(0.01)
          except:
            print("error")

    def send_message_nl(self,py2x_message):
      msg=py2x_message+'\n'
      self.sock.sendall(msg.encode('ascii',errors='replace'))
      
    def send_message(self,py2x_message):
      msg=py2x_message
      try:
          self.sock.sendall(msg.encode('ascii',errors='replace'))
      except Exception as e:
          print(e)

    def parse(self,line):
      vf.parse(line)
      
    def client_start(self):
      """start client"""
      self.sock.connect((self.HOST, self.PORT))
      handle_thread = threading.Thread(target=self.handler, args=(self.sock,), daemon=True)
      handle_thread.start()
 
    def handler(self,sock):
      """receive the message from the server and print it."""
 
      while True:
        lx=""
        while True:
          data = sock.recv(1024)
          dl=len(data)
          try:
             rd=data.decode('utf-8')
          except:
             rd='?'*dl
          for i in range(dl):
              c=rd[i]
              lx=lx+c
              if c=="." or c=="\n":
                  print("[receive] "+lx)
                  self.parseLines(lx)
                  lx=""
              #print(c)
          if c=="." or c=="\n":
              break
        print("[receive]-"+lx)
        
        if self.space!=None:
           print("parse-"+lx)
           self.parseLines(lx)
           
    def parseLines(self,ls):
        lsx=ls.splitlines()
        for i in range(len(lsx)):
            self.space.parse(lsx[i])

class Offline_Client:
    def __init__(self):
        print("start Offline_Client.__init__")
    def set_space(self,space):
        self.space=space
    def start_input_thread(self):
        handle_thread2 = threading.Thread(target=self.start_input, args=(self.space,), daemon=True)
        handle_thread2.start()
        
    def start_input(self,space):
        print("input...")
        line=""
        while True:
            try:
                line=input()
                if line=="clear.":
                    space.clear()
                elif line.startswith("print "):
                    line=line[len("print "):]   
                    while line.startswith(" "):
                        line=line[1:]
                    if line.startswith("xy."):
                        space.make_pjxy()
                    elif line.startswith("yz."):
                        space.make_pjyz()
                    elif line.startswith("zx."):
                        space.make_pjzx()
                elif line.startswith("connect "):
                    line=line[len("connect "):]   
                    while line.startswith(" "):
                        line=line[1:]
                    if line.startswith("factory."):
                        factory.client_start()
                    elif line.startswith("dice."):
                        client.client_start()
                elif line.startswith("rotate "):
                    line=line[len("rotate "):]   
                    while line.startswith(" "):
                        line=line[1:]
                    if line.startswith("z."):
                        space.rotate_z_cw_90()
                    elif line.startswith("y."):
                        space.rotate_y_cw_90()
                    elif line.startswith("x."):
                        space.rotate_x_cw_90()
                    elif line.startswith("f."):
                        space.move_and_rotate_for_factory()
                elif line.startswith("generate."):
                    proc=space.generate_assemble_procedure()
                    print("generated proc=")
                    print(proc)
                else:
                    space.parse(line)
            except Exception as e:
                print(e)
                print("error")

if __name__ == "__main__":
    client=Chat_Client()
    #client=Offline_Client()
    space=Space()
    factory=Factory_Client()
    client.set_space(space)
    space.set_factory(factory)
    #client.client_start()
    client.start_input_thread()
    client.set_factory(factory)
    space.start_3d()

}}

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS