org.mklab.mikity.android.CanvasFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.mklab.mikity.android.CanvasFragment.java

Source

/**
 * Copyright (C) 2015 MKLab.org (Koga Laboratory)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.mklab.mikity.android;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;

import org.mklab.mikity.android.control.AnimationTask;
import org.mklab.mikity.android.renderer.OpenglesObjectRenderer;
import org.mklab.mikity.control.AnimationTaskListener;
import org.mklab.mikity.model.GroupObjectManager;
import org.mklab.mikity.model.xml.Mikity3dFactory;
import org.mklab.mikity.model.xml.Mikity3dSerializeDeserializeException;
import org.mklab.mikity.model.xml.simplexml.ConfigurationModel;
import org.mklab.mikity.model.xml.simplexml.Mikity3DMarshaller;
import org.mklab.mikity.model.xml.simplexml.Mikity3DModel;
import org.mklab.mikity.model.xml.simplexml.config.EyeModel;
import org.mklab.mikity.model.xml.simplexml.config.LightModel;
import org.mklab.mikity.model.xml.simplexml.config.LookAtPointModel;
import org.mklab.mikity.model.xml.simplexml.model.AnimationModel;
import org.mklab.mikity.model.xml.simplexml.model.GroupModel;
import org.mklab.nfc.matrix.DoubleMatrix;
import org.mklab.nfc.matx.MatxMatrix;

import android.app.ProgressDialog;
import android.content.res.Configuration;
import android.opengl.GLSurfaceView;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v4.app.Fragment;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Toast;

/**
 * ??????
 * 
 * @author soda
 * @version $Revision$, 2014/10/10
 */
public class CanvasFragment extends Fragment implements View.OnTouchListener, OnScaleGestureListener {
    /**  */
    private View view;
    /** GL???? */
    GLSurfaceView glView;

    /** ????true */
    boolean isInitialScreenSize;

    /**  */
    OpenglesObjectRenderer objectRenderer;

    /** scaleGestureDetector */
    private ScaleGestureDetector gestureDetector = null;

    private boolean rotating;
    private boolean scaling;
    private float prevX = 0;
    private float prevY = 0;

    double scaleValue = 1;

    private Timer timer = new Timer();

    private double[] timeTable;

    /** ??? */
    int animationSpeedRate = 1000;

    /** ? */
    private long startTime;
    /** ? */
    private double stopTime;
    /** ?? */
    private long pausedTime;
    /** ?? */
    private long delayTime;

    /** Mikity3d */
    Mikity3DModel root;

    private GroupObjectManager manager;

    OpenglesModeler modeler;

    Map<String, DoubleMatrix> sourceData = new HashMap<String, DoubleMatrix>();

    boolean playable = true;
    private AnimationTask animationTask;

    /**  */
    ProgressDialog progressDialog;

    /** ??????true */
    private boolean isPaused = false;

    /** ????true */
    boolean isRepeating = false;

    /**
     * {@inheritDoc}
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);

        this.view = inflater.inflate(R.layout.fragment_canvas, container, false);
        this.view.setOnTouchListener(this);

        this.glView = (GLSurfaceView) this.view.findViewById(R.id.glview1);
        this.glView.setEGLConfigChooser(8, 8, 8, 8, 16, 8);

        getResources();

        final ConfigurationModel configuration = new ConfigurationModel();
        configuration.setEye(new EyeModel(5.0f, 0.0f, 0.0f));
        configuration.setLookAtPoiint(new LookAtPointModel(0.0f, 0.0f, 0.0f));
        configuration.setLight(new LightModel(10.0f, 10.0f, 20.0f));

        this.objectRenderer = new OpenglesObjectRenderer(this.glView, configuration);
        this.modeler = new OpenglesModeler(this.objectRenderer);

        this.glView.setRenderer(this.objectRenderer);
        this.glView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
        this.isInitialScreenSize = false;

        createNewModelData();

        this.gestureDetector = new ScaleGestureDetector(this.getActivity(), this);

        return this.view;
    }

    /**
     * {@inheritDoc}
     * 
     * ??????????
     */
    public boolean onTouch(View v, MotionEvent event) {
        final int touchCount = event.getPointerCount();

        // ?ScaleGestureDetector#onTouchEvent????
        this.gestureDetector.onTouchEvent(event);

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            if (((MainActivity) getActivity()).getSupportActionBar().isShowing() == false) {
                this.rotating = false;
                ((MainActivity) getActivity()).setFullScreenExitButtonEnabled(true);
                return true;
            }
            this.rotating = true;
            this.prevX = event.getX();
            this.prevY = event.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            final float moveX = event.getX() - this.prevX;
            final float moveY = event.getY() - this.prevY;
            this.prevX = event.getX();
            this.prevY = event.getY();

            if ((this.rotating) && (touchCount == 1)) {
                float rotationY = moveY / 5;
                float rotationZ = moveX / 5;
                this.objectRenderer.rotateY(rotationY);
                this.objectRenderer.rotateZ(rotationZ);
            }

            if ((touchCount == 2) && (!this.scaling)) {
                float translationY = moveX / 2000;
                float translationZ = moveY / 2000;
                this.objectRenderer.translateY(translationY);
                this.objectRenderer.translateZ(translationZ);
                this.rotating = false;
            }
            this.rotating = true;
            break;
        case MotionEvent.ACTION_UP:
            this.prevX = event.getX();
            this.prevY = event.getY();
            break;
        case MotionEvent.ACTION_CANCEL:
            break;

        default:
            break;
        }

        this.objectRenderer.updateDisplay();
        return true;
    }

    /**
     * {@inheritDoc}
     */
    public boolean onScale(ScaleGestureDetector detector) {
        this.rotating = false;
        this.scaling = true;

        final double scalingRate = 0.5;
        final double newScale = (this.scaleValue - (1.0 - this.gestureDetector.getScaleFactor())) / scalingRate;
        this.objectRenderer.setScale((float) Math.min(20.0, Math.max(0.05, newScale)));

        this.prevX = this.gestureDetector.getFocusX();
        this.prevY = this.gestureDetector.getFocusY();

        return false;
    }

    /**
     * {@inheritDoc}
     */
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        this.scaling = true;
        return true;
    }

    /**
     * {@inheritDoc}
     */
    public void onScaleEnd(ScaleGestureDetector detector) {
        this.scaling = false;

        this.scaleValue = this.scaleValue - (1.0 - this.gestureDetector.getScaleFactor());

        this.prevX = this.gestureDetector.getFocusX();
        this.prevY = this.gestureDetector.getFocusY();
    }

    /**
     * LoadModelDataTask?????
     * 
     * @author koga
     * @version $Revision$, 2016/03/07
     */
    public static interface LoadModelDataTaskCallback {
        /**
         * ???????? 
         * @param input 
         * @param fileName ??
         */
        void onSuccessLoadModelData(InputStream input, String fileName);

        /**
         * ???????
         * @param input 
         * @param fileName ??
         */
        void onFailedLoadModelData(InputStream input, String fileName);
    }

    /**
     * ???????
     * 
     * @param input ?
     * @param fileName ??
     * @param callback ?
     */
    public void loadModelDataInBackground(final InputStream input, String fileName,
            LoadModelDataTaskCallback callback) {
        final LoadModelDataTask task = new LoadModelDataTask(input, fileName, callback);
        task.execute();
    }

    /**
     * ?????
     * 
     * @param input 
     */
    boolean loadModelData(InputStream input) {
        try {
            this.root = new Mikity3dFactory().loadFile(input);
            this.manager = new GroupObjectManager();
        } catch (@SuppressWarnings("unused") Mikity3dSerializeDeserializeException e) {
            showMessageInDialog(getString(R.string.please_select_model_file));
            return false;
        }

        return true;
    }

    class LoadModelDataTask extends AsyncTask<String, Void, Boolean> {
        private InputStream input;
        private String fileName;
        private LoadModelDataTaskCallback callback;

        public LoadModelDataTask(final InputStream input, String fileName, LoadModelDataTaskCallback callback) {
            this.input = input;
            this.fileName = fileName;
            this.callback = callback;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected void onPreExecute() {
            CanvasFragment.this.progressDialog = new ProgressDialog(getActivity());
            CanvasFragment.this.progressDialog.setCanceledOnTouchOutside(false);
            CanvasFragment.this.progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            CanvasFragment.this.progressDialog.setMessage(getString(R.string.now_loading));
            CanvasFragment.this.progressDialog.show();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected Boolean doInBackground(String... arg0) {
            final boolean result = loadModelData(this.input);
            return Boolean.valueOf(result);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected void onPostExecute(Boolean result) {
            CanvasFragment.this.progressDialog.dismiss();

            if (result.booleanValue()) {
                final Toast toast = Toast.makeText(getActivity(), getString(R.string.loadedSuccessfully),
                        Toast.LENGTH_SHORT);
                toast.setGravity(Gravity.CENTER | Gravity.BOTTOM, 0, 0);
                toast.show();

                prepareRenderer();
                prepareModeler();
                prepareAnimation();

                this.callback.onSuccessLoadModelData(this.input, this.fileName);
            } else {
                this.callback.onFailedLoadModelData(this.input, this.fileName);
            }
        }
    }

    /**
     * ????
     */
    public void prepareAnimation() {
        final List<GroupModel> rootGroups = this.root.getScene(0).getGroups();
        if (hasAnimation(rootGroups)) {
            this.manager.setHasAnimation(true);
        }
    }

    /**
     * ?????
     */
    public void createNewModelData() {
        this.root = Mikity3dFactory.createModel();
        this.manager = new GroupObjectManager();

        prepareRenderer();
        prepareModeler();
        prepareAnimation();
    }

    /**
     * ???????
     * 
     * @param output ?
     * @param fileName ??
     * @param callback ?
     */
    public void saveModelDataInBackground(final OutputStream output, String fileName,
            SaveModelDataTaskCallback callback) {
        final SaveModelDataTask task = new SaveModelDataTask(output, fileName, callback);
        task.execute();
    }

    /**
     * ????
     * 
     * @param output 
     */
    boolean saveModelData(OutputStream output) {
        try {
            final Mikity3DMarshaller marshaller = new Mikity3DMarshaller(this.root);
            marshaller.marshal(output);
            return true;
        } catch (Mikity3dSerializeDeserializeException e) {
            showMessageInDialog(e.getMessage());
            return false;
        }
    }

    class SaveModelDataTask extends AsyncTask<String, Void, Boolean> {
        private OutputStream output;
        private String fileName;
        private SaveModelDataTaskCallback callback;

        public SaveModelDataTask(final OutputStream output, String fileName, SaveModelDataTaskCallback callback) {
            this.output = output;
            this.fileName = fileName;
            this.callback = callback;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected void onPreExecute() {
            CanvasFragment.this.progressDialog = new ProgressDialog(getActivity());
            CanvasFragment.this.progressDialog.setCanceledOnTouchOutside(false);
            CanvasFragment.this.progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            CanvasFragment.this.progressDialog.setMessage(getString(R.string.now_saving));
            CanvasFragment.this.progressDialog.show();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected Boolean doInBackground(String... arg0) {
            final boolean result = saveModelData(this.output);
            return Boolean.valueOf(result);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected void onPostExecute(Boolean result) {
            CanvasFragment.this.progressDialog.dismiss();

            if (result.booleanValue()) {
                final Toast toast = Toast.makeText(getActivity(), getString(R.string.savedSuccessfully),
                        Toast.LENGTH_SHORT);
                toast.setGravity(Gravity.CENTER | Gravity.BOTTOM, 0, 0);
                toast.show();

                CanvasFragment.this.modeler.setIsChanged(false);
                this.callback.onSuccessSaveModelData(this.output, this.fileName);
            } else {
                this.callback.onFailedSaveModelData(this.output, this.fileName);
            }
        }
    }

    /**
     * SaveModelDataTask?????
     * 
     * @author koga
     * @version $Revision$, 2016/03/07
     */
    public static interface SaveModelDataTaskCallback {
        /**
         * ???????? 
         * @param output 
         * @param fileName ??
         */
        void onSuccessSaveModelData(OutputStream output, String fileName);

        /**
         * ???????
         * @param output 
         * @param fileName ??
         */
        void onFailedSaveModelData(OutputStream output, String fileName);
    }

    /**
     * ???
     */
    void prepareModeler() {
        this.modeler.setRoot(this.root);
        this.modeler.setManager(this.manager);
        this.modeler.setIsChanged(false);
    }

    /**
     * ???????
     * 
     * @param input ?
     * @param filePath ?
     * @param fileName ???
     * @param sourceId ID
     * @param callback ?
     */
    public void loadSourceDataInBackground(final InputStream input, final String filePath, final String fileName,
            final String sourceId, LoadSourceDataTaskCallback callback) {
        final LoadSourceDataTask task = new LoadSourceDataTask(input, filePath, fileName, sourceId, callback);
        task.execute();
    }

    /**
     * LoadSourceDataTask?????
     * 
     * @author koga
     * @version $Revision$, 2016/03/07
     */
    public static interface LoadSourceDataTaskCallback {
        /**
         * ???????? 
         * @param sourceId ID
         * @param fileName ?? 
         */
        void onSuccessLoadSourceData(String sourceId, String fileName);

        /**
         * ???????
         * @param sourceId ID
         * @param fileName ??
         */
        void onFailedLoadSourceData(String sourceId, String fileName);
    }

    class LoadSourceDataTask extends AsyncTask<String, Void, Boolean> {
        private InputStream input;
        private String filePath;
        private String fileName;
        private String sourceId;
        private LoadSourceDataTaskCallback callback;

        public LoadSourceDataTask(final InputStream input, final String filePath, final String fileName,
                final String sourceId, LoadSourceDataTaskCallback callback) {
            this.input = input;
            this.filePath = filePath;
            this.fileName = fileName;
            this.sourceId = sourceId;
            this.callback = callback;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected void onPreExecute() {
            CanvasFragment.this.progressDialog = new ProgressDialog(getActivity());
            CanvasFragment.this.progressDialog.setCanceledOnTouchOutside(false);
            CanvasFragment.this.progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            CanvasFragment.this.progressDialog.setMessage(getString(R.string.now_loading));
            CanvasFragment.this.progressDialog.show();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected Boolean doInBackground(String... arg0) {
            final boolean result = loadSourceData(this.input, this.filePath, this.sourceId);

            // input is closed in order to complete reading the data from the input stream.
            try {
                this.input.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            return Boolean.valueOf(result);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected void onPostExecute(Boolean result) {
            CanvasFragment.this.progressDialog.dismiss();

            if (result.booleanValue()) {
                final Toast toast = Toast.makeText(getActivity(), getString(R.string.loadedSuccessfully),
                        Toast.LENGTH_SHORT);
                toast.setGravity(Gravity.CENTER | Gravity.BOTTOM, 0, 0);
                toast.show();

                addSource(this.sourceId);
                this.callback.onSuccessLoadSourceData(this.sourceId, this.fileName);
            } else {
                this.callback.onFailedLoadSourceData(this.sourceId, this.fileName);
            }
        }
    }

    /**
     * ????
     * 
     * @param input ?
     * @param filePath ?
     * @param sourceId ID
     */
    boolean loadSourceData(final InputStream input, final String filePath, final String sourceId) {
        try {
            final DoubleMatrix data;

            if (filePath.toLowerCase().endsWith(".mat") || filePath.startsWith("/document")) { //$NON-NLS-1$ //$NON-NLS-2$
                data = (DoubleMatrix) MatxMatrix.readMatFormat(new InputStreamReader(input));
            } else if (filePath.toLowerCase().endsWith(".csv") || filePath.startsWith("/document")) { //$NON-NLS-1$ //$NON-NLS-2$
                data = DoubleMatrix.readCsvFormat(new InputStreamReader(input)).transpose();
            } else if (filePath.toLowerCase().endsWith(".txt") || filePath.startsWith("/document")) { //$NON-NLS-1$ //$NON-NLS-2$
                data = DoubleMatrix.readSsvFormat(new InputStreamReader(input)).transpose();
            } else {
                data = DoubleMatrix.readSsvFormat(new InputStreamReader(input)).transpose();
            }

            this.sourceData.put(sourceId, data);

            return true;
        } catch (@SuppressWarnings("unused") IOException e) {
            if (this.progressDialog != null) {
                this.progressDialog.dismiss();
            }

            showMessageInDialog(getString(R.string.please_select_source_file));

            return false;
        }
    }

    /**
     * MovableGroupManager????
     * 
     * @param sourceId ID
     */
    public void addSource(String sourceId) {
        try {
            this.manager.addSource(sourceId, this.sourceData.get(sourceId));
        } catch (@SuppressWarnings("unused") IllegalAccessError e) {
            if (this.progressDialog != null) {
                this.progressDialog.dismiss();
            }

            final String message = "Source data size is not match model's source number." //$NON-NLS-1$
                    + "\nPlease select proper source data or set proper source number."; //$NON-NLS-1$
            showMessageInDialog(message);
        } catch (@SuppressWarnings("unused") IllegalArgumentException e) {
            if (this.progressDialog != null) {
                this.progressDialog.dismiss();
            }

            final String message = "Please select proper source data or set source number to data size or lower."; //$NON-NLS-1$
            showMessageInDialog(message);
        }
    }

    private void prepareTimeTable() {
        final int dataSize = this.manager.getDataSize();
        this.timeTable = new double[dataSize];
        this.stopTime = this.manager.getStopTime();
        for (int i = 0; i < this.timeTable.length; i++) {
            this.timeTable[i] = this.stopTime * ((double) i / this.timeTable.length);
        }
    }

    private boolean hasAnimation(List<GroupModel> groups) {
        for (final GroupModel group : groups) {
            final AnimationModel[] animations = group.getAnimations();
            for (final AnimationModel animation : animations) {
                if (animation.exists()) {
                    return true;
                }
            }
            if (hasAnimation(group.getGroups())) {
                return true;
            }
        }

        return false;
    }

    /**
     * ObjectGroupManager???
     * 
     * @return ObjectGroupManager
     */
    public GroupObjectManager getObjectGroupManager() {
        return this.manager;
    }

    /**
     * ???
     * 
     * @return 
     */
    public OpenglesObjectRenderer getObjectRender() {
        return this.objectRenderer;
    }

    /**
     * ?????
     */
    public void repeatAnimation() {
        this.isRepeating = true;
        runAnimation();
    }

    /**
     * ???
     */
    public void runAnimation() {
        if (this.manager == null) {
            showMessageInDialog(getString(R.string.modelDataIsNotReady));
            return;
        }
        if (this.manager.isSourceReady() == false) {
            showMessageInDialog(getString(R.string.sourceDataIsNotReady));
            return;
        }

        if (this.playable == false) {
            this.timer.cancel();
        }

        if (this.isPaused == false) {
            this.startTime = SystemClock.uptimeMillis();
            this.delayTime = 0;
        }

        this.manager.prepareMovingGroupObjects();

        prepareTimeTable();

        this.stopTime = this.manager.getStopTime();

        if (this.isPaused) {
            this.delayTime += SystemClock.uptimeMillis() - this.pausedTime;
        }
        this.isPaused = false;

        this.animationTask = new AnimationTask(this.startTime, this.stopTime, getObjectGroupManager(),
                getObjectRender(), this.delayTime);
        this.animationTask.setSpeedScale(this.animationSpeedRate / 1000.0);
        this.animationTask.addAnimationTaskListener(new AnimationTaskListener() {

            /**
             * {@inheritDoc}
             */
            public void tearDownAnimation() {
                CanvasFragment.this.playable = true;
                if (CanvasFragment.this.isRepeating) {
                    runAnimation();
                }
            }

            /**
             * {@inheritDoc}
             */
            public void setUpAnimation() {
                // nothing to do
            }
        });

        this.playable = false;
        this.timer = new Timer();
        this.timer.schedule(this.animationTask, 0, 30);
    }

    /**
     * ????
     */
    public void stopAnimation() {
        this.timer.cancel();
        this.playable = true;
        this.isPaused = false;
        this.isRepeating = false;
    }

    /**
     * ????
     */
    public void pauseAnimation() {
        if (this.isPaused) {
            return;
        }

        if (this.animationTask != null) {
            this.timer.cancel();
            this.isPaused = true;
            this.playable = true;
            setPuasedTime(SystemClock.uptimeMillis());
        }
    }

    /**
     * ???
     * 
     * @return 
     */
    public Mikity3DModel getRoot() {
        return this.root;
    }

    /**
     * ???
     */
    void prepareRenderer() {
        final List<GroupModel> rootGroups = this.root.getScene(0).getGroups();
        final ConfigurationModel configuration = this.root.getConfiguration(0);

        this.manager.clearGroupObjects();
        this.objectRenderer.setRootGroups(rootGroups, this.manager);
        this.objectRenderer.setConfiguration(configuration);
    }

    /**
     * ???????
     */
    public void resetToInitialState() {
        this.objectRenderer.resetToInitialState();
        this.objectRenderer.updateDisplay();
    }

    /**
     * ?????
     * 
     * @param isFloorDrawing ???true
     */
    public void setFloorDrawing(boolean isFloorDrawing) {
        if (this.root == null) {
            return;
        }
        this.root.getConfiguration(0).getBaseCoordinate().setFloorDrawing(isFloorDrawing);
    }

    /**
     * ?????
     * 
     * @return ???true
     */
    public boolean isFloorDrawing() {
        if (this.root == null) {
            return false;
        }
        return this.root.getConfiguration(0).getBaseCoordinate().isFloorDrawing();
    }

    /**
     * ?????
     * 
     * @param isShadowDrawing ???true
     */
    public void setShadowDrawing(boolean isShadowDrawing) {
        if (this.root == null) {
            return;
        }
        this.root.getConfiguration(0).getBaseCoordinate().setShadowDrawing(isShadowDrawing);
    }

    /**
     * ?????
     * 
     * @return ???true
     */
    public boolean isShadowDrawing() {
        if (this.root == null) {
            return false;
        }
        return this.root.getConfiguration(0).getBaseCoordinate().isShadowDrawing();
    }

    /**
     * ?????
     * 
     * @param isGridShowing ???true
     */
    public void setGridShowing(boolean isGridShowing) {
        if (this.root == null) {
            return;
        }
        this.root.getConfiguration(0).getBaseCoordinate().setGridShowing(isGridShowing);
    }

    /**
     * ?????
     * 
     * @return ???true
     */
    public boolean isGridShowing() {
        if (this.root == null) {
            return false;
        }
        return this.root.getConfiguration(0).getBaseCoordinate().isGridShowing();
    }

    /**
     * ?????
     * 
     * @param isAxisShowing ???true
     */
    public void setAxisShowing(boolean isAxisShowing) {
        if (this.root == null) {
            return;
        }
        this.root.getConfiguration(0).getBaseCoordinate().setAxisShowing(isAxisShowing);
    }

    /**
     * ???
     * 
     * @param configuration 
     */
    public void setConfiguration(ConfigurationModel configuration) {
        this.objectRenderer.setConfiguration(configuration);
    }

    /**
     * ?????
     * 
     * @return ???true
     */
    public boolean isAxisShowing() {
        if (this.root == null) {
            return false;
        }
        return this.root.getConfiguration(0).getBaseCoordinate().isAxisShowing();
    }

    /**
     * ?????????
     */
    private void configurateDirection() {
        final DisplayMetrics displayMetrics = new DisplayMetrics();
        getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);

        final int width = displayMetrics.widthPixels;
        final int height = displayMetrics.heightPixels;
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(width, height);
        this.glView.setLayoutParams(params);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        if (this.progressDialog != null) {
            this.progressDialog.dismiss();
        }
        configurateDirection();
    }

    /**
     * ???????
     * 
     * @param pausedTime ????
     */
    public void setPuasedTime(long pausedTime) {
        this.pausedTime = pausedTime;
    }

    /**
     * ???
     * 
     * @param message 
     */
    private void showMessageInDialog(String message) {
        final MessageDialogFragment dialog = new MessageDialogFragment();
        final Bundle arguments = new Bundle();
        arguments.putString("message", message); //$NON-NLS-1$
        dialog.setArguments(arguments);
        dialog.show(getActivity().getSupportFragmentManager(), "messageDialogFragment"); //$NON-NLS-1$
    }

    /**
     * ????????
     * 
     * @return ?????true
     */
    public boolean isModelChanged() {
        if (this.modeler == null) {
            return false;
        }
        return this.modeler.isChanged();
    }
}