powered by nequal
Home » Packages » IO_SWF » Source

IO_SWF / trunk/IO/SWF/Tag/Shape.php

Subversion URL: http://svn.openpear.org/IO_SWF/trunk/IO/SWF/Tag/Shape.php

Recent change

yoya [2932] -- 2013-02-04 01:29:08
changeStyleIndex の更新タイミングを修正

<?php
 
require_once 'IO/Bit.php';
require_once dirname(__FILE__).'/Base.php';
require_once dirname(__FILE__).'/../Type/RECT.php';
require_once dirname(__FILE__).'/../Type/FILLSTYLEARRAY.php';
require_once dirname(__FILE__).'/../Type/LINESTYLEARRAY.php';
require_once dirname(__FILE__).'/../Type/SHAPE.php';
 
class IO_SWF_Tag_Shape extends IO_SWF_Tag_Base {
    var $_shapeId = null;
    // DefineShape, DefineShape2, DefineShape3
    var $_shapeBounds;
    var $_fillStyles = array(), $_lineStyles = array();
    var $_shapeRecords = array();
    // DefineMorphShape
    var $_startBounds, $_endBounds;
    var $_offset;
    var $_morphFillStyles = array(), $_morphLineStyles = array();
    var $_startEdge, $_endEdges;
 
   function parseContent($tagCode, $content, $opts = array()) {
 
        $isMorph = ($tagCode == 46) || ($tagCode == 84);
 
        $reader = new IO_Bit();
    	$reader->input($content);
        $this->_shapeId = $reader->getUI16LE();
 
        $opts = array('tagCode' => $tagCode, 'isMorph' => $isMorph);
 
        if ($isMorph === false) {
        	// 描画スタイル
            $this->_shapeBounds = IO_SWF_TYPE_RECT::parse($reader);
            $this->_fillStyles = IO_SWF_TYPE_FILLSTYLEARRAY::parse($reader, $opts);
        	$this->_lineStyles = IO_SWF_TYPE_LINESTYLEARRAY::parse($reader, $opts);
        	// 描画枠
            $this->_shapeRecords = IO_SWF_Type_SHAPE::parse($reader, $opts);
        } else {
            $this->_startBounds = IO_SWF_TYPE_RECT::parse($reader);
            $this->_endBounds = IO_SWF_TYPE_RECT::parse($reader);
            $this->_offset = $reader->getUI32LE();
        	// 描画スタイル
            $this->_morphFillStyles = IO_SWF_TYPE_FILLSTYLEARRAY::parse($reader, $opts);
        	$this->_morphLineStyles = IO_SWF_TYPE_LINESTYLEARRAY::parse($reader, $opts);
        	// 描画枠
            $this->_startEdge = IO_SWF_Type_SHAPE::parse($reader, $opts);
            $this->_endEdge   = IO_SWF_Type_SHAPE::parse($reader, $opts);
        }
    }
 
    function dumpContent($tagCode, $opts = array()) {
        $isMorph = ($tagCode == 46) || ($tagCode == 84);
        if (is_null($this->_shapeId) === false) {
            echo "    ShapeId: {$this->_shapeId}\n";
        }
        $opts = array('tagCode' => $tagCode, 'isMorph' => $isMorph);
 
        if ($isMorph === false) {
            echo "    ShapeBounds: ". IO_SWF_Type_RECT::string($this->_shapeBounds)."\n";
            echo "    FillStyles:\n";
            echo IO_SWF_Type_FILLSTYLEARRAY::string($this->_fillStyles, $opts);
            echo "    LineStyles:\n";
            echo IO_SWF_Type_LINESTYLEARRAY::string($this->_lineStyles, $opts);
 
            echo "    ShapeRecords:\n";
            echo IO_SWF_Type_SHAPE::string($this->_shapeRecords, $opts);
        } else {
            echo "    StartBounds: ". IO_SWF_Type_RECT::string($this->_startBounds)."\n";
            echo "    EndBounds: ". IO_SWF_Type_RECT::string($this->_endBounds)."\n";
            echo "    FillStyles:\n";
            echo IO_SWF_Type_FILLSTYLEARRAY::string($this->_morphFillStyles, $opts);
            echo "    LineStyles:\n";
            echo IO_SWF_Type_LINESTYLEARRAY::string($this->_morphLineStyles, $opts);
 
            echo "    StartEdge:\n";
            echo IO_SWF_Type_SHAPE::string($this->_startEdge, $opts);
            echo "    endEdge:\n";
            echo IO_SWF_Type_SHAPE::string($this->_endEdge, $opts);
        }
    }
 
    function buildContent($tagCode, $opts = array()) {
        $isMorph = ($tagCode == 46) || ($tagCode == 84);
        $writer = new IO_Bit();
        if (isset($opts['hasShapeId']) && $opts['hasShapeId']) {
            $writer->putUI16LE($this->_shapeId);
        }
        $opts = array('tagCode' => $tagCode);
 
        if ($isMorph === false) {
            IO_SWF_Type_RECT::build($writer, $this->_shapeBounds);
            // 描画スタイル
            IO_SWF_Type_FILLSTYLEARRAY::build($writer, $this->_fillStyles, $opts);
            IO_SWF_Type_LINESTYLEARRAY::build($writer, $this->_lineStyles, $opts);
        	// 描画枠
            $opts['fillStyleCount'] = count($this->_fillStyles);
            $opts['lineStyleCount'] = count($this->_lineStyles);
            IO_SWF_Type_SHAPE::build($writer, $this->_shapeRecords, $opts);
        } else {
            IO_SWF_Type_RECT::build($writer, $this->_startBounds);
            IO_SWF_Type_RECT::build($writer, $this->_endBounds);
            // 描画スタイル
            IO_SWF_Type_FILLSTYLEARRAY::build($writer, $this->_morphFillStyles, $opts);
            IO_SWF_Type_LINESTYLEARRAY::build($writer, $this->_morphLineStyles, $opts);
        	// 描画枠
            $opts['fillStyleCount'] = count($this->_morphFillStyles);
            $opts['lineStyleCount'] = count($this->_morphLineStyles);
            IO_SWF_Type_SHAPE::build($writer, $this->_startEdge, $opts);
            IO_SWF_Type_SHAPE::build($writer, $this->_endEdge, $opts);
        }
        return $writer->output();
    }
 
    function deforme($threshold) {
        $startIndex = null;
        foreach ($this->_shapeRecords as $shapeRecordIndex => $shapeRecord) {
            if (($shapeRecord['TypeFlag'] == 0) && (isset($shapeRecord['EndOfShape']) === false)) {
                // StyleChangeRecord
                $endIndex = $shapeRecordIndex - 1;
                if (is_null($startIndex) === false) {
                    $this->deformeShapeRecordUnit($threshold, $startIndex, $endIndex);
                }
                $startIndex = $shapeRecordIndex;
            }
            if (isset($shapeRecord['EndOfShape']) && ($shapeRecord['EndOfShape']) == 0) {
                // EndShapeRecord
                $endIndex = $shapeRecordIndex - 1;
               $this->deformeShapeRecordUnit($threshold, $startIndex, $endIndex);
            }
        }
        $this->_shapeRecords = array_values($this->_shapeRecords);
    }
 
    function deformeShapeRecordUnit($threshold, $startIndex, $endIndex) {
//        return $this->deformeShapeRecordUnit_1($threshold, $startIndex, $endIndex);
        return $this->deformeShapeRecordUnit_2($threshold, $startIndex, $endIndex);
    }
    function deformeShapeRecordUnit_1($threshold, $startIndex, $endIndex) {
        $threshold_2 = $threshold * $threshold;
        $shapeRecord = $this->_shapeRecords[$startIndex];
        $prevIndex = null;
        $currentDrawingPositionX = $shapeRecord['MoveX'];
        $currentDrawingPositionY = $shapeRecord['MoveY'];
        for ($i = $startIndex + 1 ;$i <= $endIndex; $i++) {
            $shapeRecord = & $this->_shapeRecords[$i];
            if ($shapeRecord['StraightFlag'] == 0) {
                // 曲線に対する処理
                $diff_x = $shapeRecord['ControlX'] - $currentDrawingPositionX;
                $diff_y = $shapeRecord['ControlY'] - $currentDrawingPositionY;
                $distance_2_control = $diff_x * $diff_x + $diff_y * $diff_y;
                $diff_x = $shapeRecord['AnchorX'] - $currentDrawingPositionX;
                $diff_y = $shapeRecord['AnchorY'] - $currentDrawingPositionY;
                $distance_2_anchor = $diff_x * $diff_x + $diff_y * $diff_y;
//                if (max($distance_2_control, $distance_2_anchor) > $threshold_2) {
                if (($distance_2_control +  $distance_2_anchor) > $threshold_2) {
                    // 何もしない
                    $prevIndex = $i;
                    $prevDrawingPositionX = $currentDrawingPositionX;
                    $prevDrawingPositionY = $currentDrawingPositionY;
                    $currentDrawingPositionX = $shapeRecord['AnchorX'];
                    $currentDrawingPositionY = $shapeRecord['AnchorY'];
                    continue; // skip
                }
                // 直線に変換する
                $shapeRecord['StraightFlag'] = 1; // to Straight
                $shapeRecord['X'] = $shapeRecord['AnchorX'];
                $shapeRecord['Y'] = $shapeRecord['AnchorY'];
                unset($shapeRecord['ControlX'], $shapeRecord['ControlY']);
                unset($shapeRecord['AnchorX'], $shapeRecord['AnchorY']);
            }
            if (is_null($prevIndex)) {
                // 何もしない
                $prevIndex = $i;
                $prevDrawingPositionX = $currentDrawingPositionX;
                $prevDrawingPositionY = $currentDrawingPositionY;
                $currentDrawingPositionX = $shapeRecord['X'];
                $currentDrawingPositionY = $shapeRecord['Y'];
                continue; // skip
            }
            $diff_x = $shapeRecord['X'] - $prevDrawingPositionX;
            $diff_y = $shapeRecord['Y'] - $prevDrawingPositionY;
            $distance_2 = $diff_x * $diff_x + $diff_y * $diff_y;
            if ($distance_2 > $threshold_2) {
                // 何もしない
                $prevIndex = $i;
                $prevDrawingPositionX = $currentDrawingPositionX;
                $prevDrawingPositionY = $currentDrawingPositionY;
                $currentDrawingPositionX = $shapeRecord['X'];
                $currentDrawingPositionY = $shapeRecord['Y'];
                continue; // skip
            }
            // 前の直線にくっつける。
            $prevShapeRecord = & $this->_shapeRecords[$prevIndex];
            $prevShapeRecord['X'] = $shapeRecord['X'];
            $prevShapeRecord['Y'] = $shapeRecord['Y'];
            $currentDrawingPositionX = $shapeRecord['X'];
            $currentDrawingPositionY = $shapeRecord['Y'];
            unset($this->_shapeRecords[$i]);
        }
    }
 
    function deformeShapeRecordUnit_2($threshold, $startIndex, $endIndex) {
        $this->deformeShapeRecordUnit_2_curve($threshold, $startIndex, $endIndex);
        while ($this->deformeShapeRecordUnit_2_line($threshold, $startIndex, $endIndex));
    }
 
    function deformeShapeRecordUnit_2_curve($threshold, $startIndex, $endIndex) {
        $threshold_2 = $threshold * $threshold;
        $shapeRecord = $this->_shapeRecords[$startIndex];
        $currentDrawingPositionX = $shapeRecord['MoveX'];
        $currentDrawingPositionY = $shapeRecord['MoveY'];
        for ($i = $startIndex + 1 ;$i <= $endIndex; $i++) {
            $shapeRecord = & $this->_shapeRecords[$i];
            if ($shapeRecord['StraightFlag'] == 0) {
            // 曲線に対する処理
                $diff_x = $shapeRecord['ControlX'] - $currentDrawingPositionX;
                $diff_y = $shapeRecord['ControlY'] - $currentDrawingPositionY;
                $distance_2_control = $diff_x * $diff_x + $diff_y * $diff_y;
                $diff_x = $shapeRecord['AnchorX'] - $currentDrawingPositionX;
                $diff_y = $shapeRecord['AnchorY'] - $currentDrawingPositionY;
                $distance_2_anchor = $diff_x * $diff_x + $diff_y * $diff_y;
                if (($distance_2_control +  $distance_2_anchor) > $threshold_2) {
                    // 何もしない
                    $currentDrawingPositionX = $shapeRecord['AnchorX'];
                    $currentDrawingPositionY = $shapeRecord['AnchorY'];
                    continue; // skip
                }
                // 直線に変換する
                $shapeRecord['StraightFlag'] = 1; // to Straight
                $shapeRecord['X'] = $shapeRecord['AnchorX'];
                $shapeRecord['Y'] = $shapeRecord['AnchorY'];
                unset($shapeRecord['ControlX'], $shapeRecord['ControlY']);
                unset($shapeRecord['AnchorX'], $shapeRecord['AnchorY']);
                $currentDrawingPositionX = $shapeRecord['X'];
                $currentDrawingPositionY = $shapeRecord['Y'];
            }
        }
    }
 
    function deformeShapeRecordUnit_2_line($threshold, $startIndex, $endIndex) {
        $threshold_2 = $threshold * $threshold;
        $shapeRecord = $this->_shapeRecords[$startIndex];
        $prevIndex = null;
        $currentDrawingPositionX = $shapeRecord['MoveX'];
        $currentDrawingPositionY = $shapeRecord['MoveY'];
        $distance_list_short = array();
        $distance_table_all = array();
        for ($i = $startIndex + 1 ;$i <= $endIndex; $i++) {
            $shapeRecord = & $this->_shapeRecords[$i];
            if ($shapeRecord['StraightFlag'] == 0) {
                $diff_x = $shapeRecord['ControlX'] - $currentDrawingPositionX;
                $diff_y = $shapeRecord['ControlY'] - $currentDrawingPositionY;
                $distance_2_control = $diff_x * $diff_x + $diff_y * $diff_y;
                $diff_x = $shapeRecord['AnchorX'] - $currentDrawingPositionX;
                $diff_y = $shapeRecord['AnchorY'] - $currentDrawingPositionY;
                $distance_2_anchor = $diff_x * $diff_x + $diff_y * $diff_y;
//                $distance_list[$i] = $distance_2_control +  $distance_2_anchor;
                $distance_table_all[$i] = $distance_2_control +  $distance_2_anchor;
                $currentDrawingPositionX = $shapeRecord['AnchorX'];
                $currentDrawingPositionY = $shapeRecord['AnchorY'];
            } else {
                $diff_x = $shapeRecord['X'] - $currentDrawingPositionX;
                $diff_y = $shapeRecord['Y'] - $currentDrawingPositionY;
            $distance_2 = $diff_x * $diff_x + $diff_y * $diff_y;
            if ($distance_2 < $threshold_2) {
               $distance_list_short[] = $i;
            }
            $distance_table_all[$i] = $distance_2;
            $currentDrawingPositionX = $shapeRecord['X'];
            $currentDrawingPositionY = $shapeRecord['Y'];
        }
    }
    sort($distance_list_short);
    $deforme_number = 0;
    foreach ($distance_list_short as $i) {
        $distance_2 = $distance_table_all[$i];
        if ($distance_2 > $threshold_2) {
            continue; // 一定距離以上の線分は処理しない
        }
        if (empty($distance_list_all[$i-1]) && empty($distance_list_all[$i+1])) {
            // 隣の線分が吸収され済みor曲線の場合は処理しない
 
        }
        $index_to_merge;
        if (empty($distance_list_all[$i-1])) {
            if (empty($distance_list_all[$i+1])) {
                // 隣の線分が吸収されている場合は処理しない
                continue;           
            } else {
                $index_to_merge = $i+1;
            }
        } else {
            if (empty($distance_list_all[$i+1])) {
                $index_to_merge = $i-1;
            } else {
                $index_to_merge = $i-1; // XXX 後で選択する処理を入れる
            }
        }
        // line merge 処理
        $shapeRecord = $this->_shapeRecords[$i];
        $shapeRecord_toMerge = & $this->_shapeRecords[$index_to_merge];
        if ($i > $index_to_merge) {
            if ($shapeRecord['StraightFlag']) {
                $shapeRecord_toMerge['X'] = $shapeRecord['X'];
                $shapeRecord_toMerge['Y'] = $shapeRecord['Y'];
            } else {
                $shapeRecord_toMerge['AnchorX'] = $shapeRecord['X'];
                $shapeRecord_toMerge['AnchorY'] = $shapeRecord['Y'];
            }
        }
        $distance_list_all[$index_to_merge] += $distance_list_all[$i];
//        unset($distance_list_all[$i]);
          unset($this->_shapeRecords[$i]);
          $deforme_number += 1;
        }
        return $deforme_number;
    }
}