com.generalrobotix.ui.item.GrxModelItem.java Source code

Java tutorial

Introduction

Here is the source code for com.generalrobotix.ui.item.GrxModelItem.java

Source

/*
 * Copyright (c) 2008, AIST, the University of Tokyo and General Robotix Inc.
 * All rights reserved. This program is made available under the terms of the
 * Eclipse Public License v1.0 which accompanies this distribution, and is
 * available at http://www.eclipse.org/legal/epl-v10.html
 * Contributors:
 * General Robotix Inc.
 * National Institute of Advanced Industrial Science and Technology (AIST)
 */

/*
 *  GrxModelItem.java
 *
 *  @author Yuichiro Kawasumi (General Robotix, Inc.)
 *  @author Shin'ichiro Nakaoka (AIST)
 */

package com.generalrobotix.ui.item;

import java.io.File;
import java.io.IOException;
import java.util.*;

import javax.media.j3d.*;
import javax.vecmath.*;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.FileDialog;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.generalrobotix.ui.grxui.GrxUIPerspectiveFactory;
import com.generalrobotix.ui.*;
import com.generalrobotix.ui.util.*;
import com.generalrobotix.ui.util.AxisAngle4d;
import com.generalrobotix.ui.view.tdview.*;
import com.generalrobotix.ui.view.vsensor.Camera_impl;

import jp.go.aist.hrp.simulator.*;
import jp.go.aist.hrp.simulator.ModelLoaderPackage.AABBdataType;
import jp.go.aist.hrp.simulator.ModelLoaderPackage.ModelLoadOption;
import jp.go.aist.hrp.simulator.ModelLoaderPackage.ModelLoaderException;

@SuppressWarnings({ "unchecked", "serial" }) //$NON-NLS-1$ //$NON-NLS-2$
/**
 * @brief item corresponds to a robot model
 */
public class GrxModelItem extends GrxBaseItem implements Manipulatable {
    public static final String TITLE = "Model"; //$NON-NLS-1$
    public static final String DEFAULT_DIR = "/../model"; //$NON-NLS-1$
    public static final String FILE_EXTENSION = "*"; //$NON-NLS-1$
    private static final double DEFAULT_RADIUS = 0.05;

    // icons
    private static final String robotIcon = "robot.png"; //$NON-NLS-1$
    private static final String envIcon = "environment.png"; //$NON-NLS-1$

    private boolean isRobot_ = true;

    private BodyInfo bInfo_;
    private boolean bModified_ = false; //< true if this model is modified, false otherwise

    public BranchGroup bgRoot_ = new BranchGroup();
    public Vector<GrxLinkItem> links_ = new Vector<GrxLinkItem>();
    public Vector<GrxExtraJointItem> extraJoints_ = new Vector<GrxExtraJointItem>();
    // jontId -> link
    private int[] jointToLink_;
    public Map<String, GrxLinkItem> nameToLink_ = new HashMap<String, GrxLinkItem>();

    // list of cameras
    private List<Camera_impl> cameraList_ = new ArrayList<Camera_impl>();

    public ShapeInfo[] shapes = null;
    public AppearanceInfo[] appearances = null;
    public MaterialInfo[] materials = null;
    public TextureInfo[] textures = null;

    // CoM
    private Switch switchCom_;
    private TransformGroup tgCom_;

    // CoM projected on the floor
    private Switch switchComZ0_;
    private TransformGroup tgComZ0_;

    // bounding box of the whole body
    private Switch switchBb_;

    /**
     * @brief notify this model is modified
     */
    public void notifyModified() {
        //System.out.println(getName()+" : modification is notified");
        notifyObservers("Modified");
        bModified_ = true;
    }

    public boolean isModified() {
        return bModified_;
    }

    public static final int MODIFIED_OK = 0;
    public static final int MODIFIED_NG = 1;
    public static final int MODIFIED_NOT = 2;

    public int checkModifiedModel(boolean reload) {
        if (bModified_) {
            String mes = MessageBundle.get("GrxProjectItem.dialog.message.changeModel.mes"); //$NON-NLS-1$
            mes = NLS.bind(mes, new String[] { getName() });

            MessageDialog msgDlg = new MessageDialog(GrxUIPerspectiveFactory.getCurrentShell(),
                    MessageBundle.get("GrxProjectItem.dialog.message.changeModel.title"), null, mes,
                    MessageDialog.INFORMATION,
                    new String[] { MessageBundle.get("GrxProjectItem.dialog.message.changeModel.btn.save"),
                            MessageBundle.get("GrxProjectItem.dialog.message.changeModel.btn.reverse"),
                            MessageBundle.get("GrxProjectItem.dialog.message.changeModel.btn.cancel") },
                    2);

            switch (msgDlg.open()) {
            case 0:
                if (reload) {
                    if (!saveAndLoad())
                        return MODIFIED_NG;
                    else
                        return MODIFIED_OK;
                } else {
                    if (!_saveAs())
                        return MODIFIED_NG;
                    cancelModified();
                    return MODIFIED_OK;
                }
            case 1:
                if (reload) {
                    if (!reload())
                        return MODIFIED_NG;
                    else
                        return MODIFIED_OK;
                } else {
                    cancelModified();
                    return MODIFIED_OK;
                }
            case 2:
            default:
                return MODIFIED_NG;
            }
        }
        return MODIFIED_NOT;
    }

    public void cancelModified() {
        bModified_ = false;
        notifyObservers("ClearModified");
    }

    public boolean saveAndLoad() {
        if (!_saveAs())
            return false;
        reload();
        return true;
    }

    public boolean reload() {
        File f = new File(getURL(true));
        load0(f);
        sameUrlModelLoad();
        return true;
    }

    private void sameUrlModelLoad() {
        File f = new File(getURL(true));
        List<GrxModelItem> sameModels = getSameUrlModels();
        Iterator<GrxModelItem> it = sameModels.iterator();
        while (it.hasNext()) {
            it.next().load0(f);
        }
    }

    /**
     * @brief get BodyInfo
     * @return BodyInfo
     */
    public BodyInfo getBodyInfo() {
        String url = getURL(true);
        if (bModified_ || url == null || url.equals("")) //$NON-NLS-1$
            return null;
        else
            return bInfo_;
    }

    /**
       * @brief
       */
    class MenuChangeType extends Action {
        public MenuChangeType() {
            if (isRobot_) {
                setText(MessageBundle.get("GrxModelItem.menu.changeEnv")); //$NON-NLS-1$
            } else {
                setText(MessageBundle.get("GrxModelItem.menu.changeRobot")); //$NON-NLS-1$
            }
        }

        public void run() {
            _setModelType(!isRobot_);
        }
    };

    MenuChangeType menuChangeType_ = new MenuChangeType();

    /**
     * @brief constructor
     * @param name name of this item
     * @param item plugin manager
     */
    public GrxModelItem(String name, GrxPluginManager item) {
        super(name, item);
        setIcon(robotIcon);
        _initMenu();

        bgRoot_.setCapability(BranchGroup.ALLOW_DETACH);
        bgRoot_.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
        bgRoot_.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
        bgRoot_.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);

        // create root link
        GrxLinkItem link = new GrxLinkItem("root", manager_, this); //$NON-NLS-1$
        manager_.itemChange(link, GrxPluginManager.ADD_ITEM);
        link.jointType("free"); //$NON-NLS-1$
        bgRoot_.addChild(link.bg_);

        setProperty("url", ""); //$NON-NLS-1$ //$NON-NLS-2$

        _setupMarks();
    }

    /**
     * @brief add a link
     * 
     * This method is called by constructor of GrxLinkItem
     * @param link link to be added
     */
    public void addLink(GrxLinkItem link) {
        //System.out.println("link is added : "+link.getName());
        links_.add(link);
        notifyModified();
    }

    /**
     * @brief remove a link
     * @param link linke to be removed
     */
    public void removeLink(GrxLinkItem link) {
        //System.out.println("link is removed : "+link.getName());
        links_.remove(link);
        notifyModified();
    }

    /**
     * @brief initialize right-click menu
     */
    private void _initMenu() {
        // menu item : reload
        setMenuItem(new Action() {
            public String getText() {
                return MessageBundle.get("GrxModelItem.menu.reload"); //$NON-NLS-1$
            }

            public void run() {
                boolean ret = load0(file_);
                if (ret) {
                    List<GrxModelItem> sameModels = getSameUrlModels();
                    Iterator<GrxModelItem> it = sameModels.iterator();
                    while (it.hasNext()) {
                        it.next().load0(file_);
                    }
                }
            }
        });

        setMenuItem(menuChangeType_);

        // menu item : save
        setMenuItem(new Action() {
            public String getText() {
                return MessageBundle.get("GrxModelItem.menu.save"); //$NON-NLS-1$
            }

            public void run() {
                String url = getStr("url"); //$NON-NLS-1$
                if (url == null || url.equals("")) { //$NON-NLS-1$
                    _saveAs();
                } else {
                    GrxVrmlExporter.export(GrxModelItem.this, url);
                }
                if (bModified_)
                    reload();
                else
                    sameUrlModelLoad();
            }
        });

        // menu item : save as
        setMenuItem(new Action() {
            public String getText() {
                return MessageBundle.get("GrxModelItem.menu.saveAs"); //$NON-NLS-1$
            }

            public void run() {
                _saveAs();
                if (bModified_)
                    reload();
                else
                    sameUrlModelLoad();
            }
        });

        // menu item : add ExtraJoint
        setMenuItem(new Action() {
            public String getText() {
                return MessageBundle.get("GrxModelItem.menu.addExtraJoint"); //$NON-NLS-1$
            }

            public void run() {
                InputDialog dialog = new InputDialog(null, getText(),
                        MessageBundle.get("GrxModelItem.dialog.message.extraJointName"), null, null); //$NON-NLS-1$
                if (dialog.open() == InputDialog.OK && dialog.getValue() != null)
                    addExtraJoint(dialog.getValue());
            }
        });

        /* disable copy and paste menus until they are implemented
        // menu item : copy
        setMenuItem( new Action(){
        public String getText(){
            return "copy";
        }
        public void run(){
            GrxDebugUtil.println("GrxModelItem.GrxModelItem copy Action");
            manager_.setSelectedGrxBaseItemList();
        }
        });
            
        // menu item : paste
        setMenuItem(new Action(){
        public String getText(){
            return "paste";
        }
            
        public void run(){
        }
        });
        */
    }

    /**
     * @brief save this model as a VRML file
     */
    private boolean _saveAs() {
        FileDialog fdlg = new FileDialog(GrxUIPerspectiveFactory.getCurrentShell(), SWT.SAVE);
        fdlg.setFilterPath(getDefaultDir().getAbsolutePath());
        String fPath = fdlg.open();
        if (fPath != null) {
            fPath = fPath.replace('\\', '/');
            if (GrxVrmlExporter.export(GrxModelItem.this, fPath)) {
                setURL(fPath);
                setDefaultDirectory(new File(fPath).getParent());
            }
            return true;
        } else
            return false;
    }

    /**
     * @brief create a new model
     * @return true if created successfully, false otherwise
     */
    public boolean create() {
        return true;
    }

    /**
     * @brief get root link
     */
    public GrxLinkItem rootLink() {
        if (links_.size() > 0) {
            return links_.get(0);
        } else {
            return null;
        }
    }

    /**
     * @brief restore properties
     */
    public void restoreProperties() {
        //super.restoreProperties();   NumOfAABB??propertyChanged?????????ModelItem??????  //
        boolean flg = false;
        if (element_ != null) {
            NodeList props = element_.getElementsByTagName(PROPERTY_TAG);
            for (int j = 0; j < props.getLength(); j++) {
                Element propEl = (Element) props.item(j);
                String key = propEl.getAttribute("name"); //$NON-NLS-1$
                String val = propEl.getAttribute("value"); //$NON-NLS-1$
                if (key.contains("NumOfAABB")) {
                    setProperty(key, val);
                    String[] linkName = key.split("\\.");
                    nameToLink_.get(linkName[0]).setProperty("NumOfAABB", val);
                    flg = true;
                } else {
                    if (!propertyChanged(key, val)) {
                        setProperty(key, val);
                    }
                }
            }
        }
        /////////////
        if (getStr("markRadius") == null) //$NON-NLS-1$
            setDbl("markRadius", DEFAULT_RADIUS); //$NON-NLS-1$

        _setModelType(isTrue("isRobot", isRobot_)); //$NON-NLS-1$

        if (getDblAry(rootLink().getName() + ".translation", null) == null && //$NON-NLS-1$
                getDblAry(rootLink().getName() + ".rotation", null) == null) //$NON-NLS-1$
            updateInitialTransformRoot();

        for (int i = 0; i < jointToLink_.length; i++) {
            GrxLinkItem l = links_.get(jointToLink_[i]);
            Double d = getDbl(l.getName() + ".angle", null); //$NON-NLS-1$
            if (d == null)
                setDbl(l.getName() + ".angle", 0.0); //$NON-NLS-1$
        }

        if (flg)
            makeAABBforSameUrlModels();

        for (int i = 0; i < links_.size(); i++) {
            GrxLinkItem l = links_.get(i);
            if (!l.jointType_.equals("fixed")) {
                String s = this.getProperty(l.getName() + ".mode", null); //$NON-NLS-1$
                if (s == null)
                    setProperty(l.getName() + ".mode", "Torque"); //$NON-NLS-1$
            }
        }
    }

    /**
     * @brief check validity of new value of property and update if valid
     * @param property name of property
     * @param value value of property
     * @return true if checked(even if value is not used), false otherwise
     */
    public boolean propertyChanged(String property, String value) {
        if (super.propertyChanged(property, value)) {
        } else if (property.equals("isRobot")) { //$NON-NLS-1$
            _setModelType(value);
        } else if (property.equals("controlTime")) { //$NON-NLS-1$
            try {
                double t = Double.parseDouble(value);
                if (t > 0) {
                    setProperty("controlTime", value); //$NON-NLS-1$
                }
            } catch (Exception ex) {
            }
        } else if (property.equals(rootLink().getName() + ".translation")) { //$NON-NLS-1$
            if (rootLink().localTranslation(value)) {
                setProperty(rootLink().getName() + ".translation", value); //$NON-NLS-1$
                calcForwardKinematics();
            }
        } else if (property.equals(rootLink().getName() + ".rotation")) { //$NON-NLS-1$
            if (rootLink().localRotation(value)) {
                setProperty(rootLink().getName() + ".rotation", value); //$NON-NLS-1$
                calcForwardKinematics();
            }
        } else if (property.equals(rootLink().getName() + ".velocity")) { //$NON-NLS-1$
            setProperty(rootLink().getName() + ".velocity", value); //$NON-NLS-1$
            rootLink().setProperty("velocity", value);
        } else if (property.equals(rootLink().getName() + ".angularVelocity")) { //$NON-NLS-1$
            setProperty(rootLink().getName() + ".angularVelocity", value); //$NON-NLS-1$
            rootLink().setProperty("angulaerVelocity", value);
        } else {
            for (int j = 0; j < links_.size(); j++) {
                GrxLinkItem link = links_.get(j);
                if (property.equals(link.getName() + ".angle")) { //$NON-NLS-1$
                    if (link.jointValue(value)) {
                        calcForwardKinematics();
                        setProperty(link.getName() + ".angle", value); //$NON-NLS-1$
                    }
                    return true;
                } else if (property.equals(link.getName() + ".jointVelocity")) { //$NON-NLS-1$
                    setProperty(link.getName() + ".jointVelocity", value); //$NON-NLS-1$
                    link.setProperty("jointVelocity", value);
                    return true;
                } else if (property.equals(link.getName() + ".NumOfAABB")) { //$NON-NLS-1$
                    if (link.propertyChanged("NumOfAABB", value)) {
                        setProperty(link.getName() + ".NumOfAABB", value); //$NON-NLS-1$
                    }
                    return true;
                } else if (property.equals(link.getName() + ".mode")) { //$NON-NLS-1$
                    setProperty(link.getName() + ".mode", value); //$NON-NLS-1$
                    link.setProperty("mode", value);
                    return true;
                }
            }
            return false;
        }
        return true;

    }

    /**
     * @brief set model type(robot or environment) from String
     * @param value "true" or "false"
     */
    private void _setModelType(String value) {
        Boolean b = Boolean.parseBoolean(value);
        if (b != null) {
            _setModelType(b);
        }
    }

    /**
     * @brief set model type(robot or environment)
     * @param isRobot true if this model is robot, false otherwise
     */
    private void _setModelType(boolean isRobot) {
        isRobot_ = isRobot;
        if (isRobot_) {
            setIcon(robotIcon);
            menuChangeType_.setText(MessageBundle.get("GrxModelItem.menu.changeEnv")); //$NON-NLS-1$
        } else {
            menuChangeType_.setText(MessageBundle.get("GrxModelItem.menu.changeRobot")); //$NON-NLS-1$
            setIcon(envIcon);
            setVisibleCoM(false);
            setVisibleCoMonFloor(false);
        }
        setProperty("isRobot", String.valueOf(isRobot_)); //$NON-NLS-1$
    }

    /**
     * @brief create spheres to display CoM and projected CoM
     * 
     * @note switches for CoM spheres and bounding box are attached to TransformGroup of
     * the root link. As the result, this method must be called after the root link is
     * created. And if the root link is re-created, this function must be called again.
     */
    private void _setupMarks() {
        double radius = getDbl("markRadius", DEFAULT_RADIUS); //$NON-NLS-1$
        switchCom_ = GrxShapeUtil.createBall(radius, new Color3f(1.0f, 1.0f, 0.0f));
        switchComZ0_ = GrxShapeUtil.createBall(radius, new Color3f(0.0f, 1.0f, 0.0f));
        tgCom_ = (TransformGroup) switchCom_.getChild(0);
        tgComZ0_ = (TransformGroup) switchComZ0_.getChild(0);
        TransformGroup root = getTransformGroupRoot();
        root.addChild(switchCom_);
        root.addChild(switchComZ0_);

        SceneGraphModifier modifier = SceneGraphModifier.getInstance();
        modifier.init_ = true;
        modifier.mode_ = SceneGraphModifier.CREATE_BOUNDS;

        Color3f color = new Color3f(0.0f, 1.0f, 0.0f);
        switchBb_ = SceneGraphModifier._makeSwitchNode(modifier._makeBoundingBox(color));
        root.addChild(switchBb_);

    }

    /**
     * @brief load a model from file
     * @param f file that describes a model
     * @return true if loaded successfully, false otherwise
     */
    public boolean load(File f) {
        boolean ret = load0(f);
        if (ret) {
            List<GrxModelItem> sameModels = getSameUrlModels();
            if (!sameModels.isEmpty()) {
                GrxModelItem model = sameModels.get(0);
                boolean flg = false;
                for (int i = 0; i < model.links_.size(); i++) {
                    if (!model.links_.get(i).getStr("NumOfAABB").equals("original data")) {
                        links_.get(i).setInt("NumOfAABB", model.links_.get(i).getInt("NumOfAABB", 1));
                        setInt(links_.get(i).getName() + ".NumOfAABB", model.links_.get(i).getInt("NumOfAABB", 1));
                        flg = true;
                    }
                }
                if (flg) {
                    BodyInfo bodyInfo = model.getBodyInfoFromModelLoader();
                    makeAABB(bodyInfo);
                }
            }
            return true;
        } else
            return false;

    }

    private boolean load0(File f) {
        long load_stime = System.currentTimeMillis();
        file_ = f;
        String url = null;
        try {
            url = f.getCanonicalPath();
        } catch (IOException e) {
            e.printStackTrace();
        }
        GrxDebugUtil.println("Loading " + url); //$NON-NLS-1$
        try {
            ModelLoader mloader = ModelLoaderHelper.narrow(GrxCorbaUtil.getReference("ModelLoader")); //$NON-NLS-1$
            mloader._non_existent();
            setURL(url);
            bInfo_ = mloader.loadBodyInfo(getURL(true));
            boolean ret = registerCharacter();
            long load_etime = System.currentTimeMillis();
            System.out.println("load time = " + (load_etime - load_stime) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
            return ret;
        } catch (ModelLoaderException me) {
            MessageDialog.openError(GrxUIPerspectiveFactory.getCurrentShell(),
                    MessageBundle.get("GrxModelItem.dialog.title.error"), //$NON-NLS-1$
                    MessageBundle.get("GrxModelItem.dialog.message.loadError") + "\n" + //$NON-NLS-1$ //$NON-NLS-2$
                            url + "\n\n" + me.description); //$NON-NLS-1$
            System.out.println("Failed to load vrml model:" + url); //$NON-NLS-1$
            me.printStackTrace();
            return false;
        } catch (Exception ex) {
            MessageDialog.openError(GrxUIPerspectiveFactory.getCurrentShell(),
                    MessageBundle.get("GrxModelItem.dialog.title.error"), //$NON-NLS-1$
                    MessageBundle.get("GrxModelItem.dialog.message.NoModelLoader"));
            System.out.println("Failed to load vrml model:" + url); //$NON-NLS-1$
            ex.printStackTrace();
            return false;
        }
    }

    public boolean registerCharacter(BodyInfo bInfo) {
        bInfo_ = bInfo;
        return registerCharacter();
    }

    private boolean registerCharacter() {
        manager_.focusedItem(null);
        manager_.setSelectedItem(this, false);
        bgRoot_.detach();
        bgRoot_ = new BranchGroup();
        bgRoot_.setCapability(BranchGroup.ALLOW_DETACH);
        bgRoot_.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
        bgRoot_.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
        bgRoot_.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);

        LinkInfo[] linkInfoList = bInfo_.links();

        // delete existing model data
        if (rootLink() != null) {
            rootLink().delete();
        }

        for (int i = 0; i < cameraList_.size(); i++) {
            cameraList_.get(i).destroy();
        }
        cameraList_.clear();

        int jointCount = 0;
        nameToLink_.clear();

        int massZeroLink = -1;
        for (int i = 0; i < linkInfoList.length; i++) {
            GrxLinkItem link = new GrxLinkItem(linkInfoList[i].name, manager_, this, linkInfoList[i]);
            manager_.itemChange(link, GrxPluginManager.ADD_ITEM);
            if (link.jointId_ >= 0) {
                jointCount++;
            }
            nameToLink_.put(link.getName(), link);
            if (linkInfoList[i].mass <= 0.0)
                massZeroLink = i;
        }
        if (massZeroLink >= 0)
            MessageDialog.openWarning(null, getName(), linkInfoList[massZeroLink].name + "::"
                    + MessageBundle.get("GrxModelItem.dialog.message.massZero"));
        System.out.println("links_.size() = " + links_.size()); //$NON-NLS-1$

        // Search root node.
        int rootIndex = -1;
        for (int i = 0; i < links_.size(); i++) {
            if (links_.get(i).parentIndex_ < 0) {
                if (rootIndex < 0) {
                    rootIndex = i;
                } else {
                    System.out.println("Error. Two or more root node exist."); //$NON-NLS-1$
                }
            }
        }
        if (rootIndex < 0) {
            System.out.println("Error, root node doesn't exist."); //$NON-NLS-1$
        }

        createLink(rootIndex);

        jointToLink_ = new int[jointCount];
        for (int i = 0; i < jointCount; i++) {
            for (int j = 0; j < links_.size(); j++) {
                if (links_.get(j).jointId_ == i) {
                    jointToLink_[i] = j;
                }
            }
        }

        ExtraJointInfo[] extraJointList = bInfo_.extraJoints();
        extraJoints_.clear();
        for (int i = 0; i < extraJointList.length; i++) {
            GrxExtraJointItem extraJoint = new GrxExtraJointItem(extraJointList[i].name, manager_, this,
                    extraJointList[i]);
            extraJoints_.add(extraJoint);
            manager_.itemChange(extraJoint, GrxPluginManager.ADD_ITEM);
        }

        long stime = System.currentTimeMillis();
        try {
            _loadVrmlScene(linkInfoList);
        } catch (BadLinkStructureException e) {
            e.printStackTrace();
            return false;
        }
        long etime = System.currentTimeMillis();
        System.out.println("_loadVrmlScene time = " + (etime - stime) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$

        calcForwardKinematics();
        updateInitialTransformRoot();
        updateInitialJointValues();

        _setupMarks();
        setProperty("isRobot", Boolean.toString(isRobot_)); //$NON-NLS-1$
        for (int i = 0; i < links_.size(); i++) {
            GrxLinkItem l = links_.get(i);
            if (!l.jointType_.equals("fixed")) {
                setProperty(l.getName() + ".mode", "Torque"); //$NON-NLS-1$
                l.setProperty("mode", "Torque");
            }
        }

        manager_.setSelectedItem(this, true);
        cancelModified();
        return true;
    }

    /**
     * @brief make connections between links and gather cameras 
     * @param index index of link in links_
     */
    private void createLink(int index) {

        GrxLinkItem link = links_.get(index);

        // register this to children field of parent link
        if (link.parentIndex_ != -1) {
            links_.get(link.parentIndex_).addLink(link);
        } else {
            bgRoot_.addChild(link.bg_);
        }

        // gather cameras
        for (int i = 0; i < link.children_.size(); i++) {
            if (link.children_.get(i) instanceof GrxSensorItem) {
                GrxSensorItem sensor = (GrxSensorItem) link.children_.get(i);
                if (sensor.isCamera()) {
                    cameraList_.add(sensor.getCamera());
                }
            }
        }

        for (int i = 0; i < link.childIndices_.length; i++) {
            // call recursively
            int childIndex = link.childIndices_[i];
            createLink(childIndex);
        }
    }

    /**
     * @brief create shapes of links
     * @param links array of LinkInfo retrieved from ModelLoader
     * @throws BadLinkStructureException
     */
    private void _loadVrmlScene(LinkInfo[] links) throws BadLinkStructureException {
        shapes = bInfo_.shapes();
        appearances = bInfo_.appearances();
        materials = bInfo_.materials();
        textures = bInfo_.textures();

        int numLinks = links.length;
        for (int linkIndex = 0; linkIndex < numLinks; linkIndex++) {
            GrxLinkItem link = links_.get(linkIndex);
            for (int i = 0; i < link.children_.size(); i++) {
                if (link.children_.get(i) instanceof GrxSegmentItem) {
                    GrxSegmentItem segment = (GrxSegmentItem) link.children_.get(i);
                    segment.addShape(segment.getTransform());
                } else if (link.children_.get(i) instanceof GrxSensorItem) {
                    GrxSensorItem sensor = (GrxSensorItem) link.children_.get(i);
                    sensor.addShape(new Matrix4d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1));
                } else if (link.children_.get(i) instanceof GrxHwcItem) {
                    GrxHwcItem hwc = (GrxHwcItem) link.children_.get(i);
                    hwc.addShape(new Matrix4d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1));
                }
            }
        }
        setDblAry(rootLink().getName() + ".translation", rootLink().localTranslation()); //$NON-NLS-1$
        setDblAry(rootLink().getName() + ".rotation", rootLink().localRotation()); //$NON-NLS-1$
        setDblAry(rootLink().getName() + ".velocity", new double[] { 0, 0, 0 }); //$NON-NLS-1$
        setDblAry(rootLink().getName() + ".angularVelocity", new double[] { 0, 0, 0 }); //$NON-NLS-1$

        for (int i = 0; i < links_.size(); i++) {
            Node n = links_.get(i).tg_.getChild(0);
            if (n.getCapability(Node.ENABLE_PICK_REPORTING))
                n.clearCapability(Node.ENABLE_PICK_REPORTING);
        }

    }

    /**
     * @brief load and add a new robot as a child
     * @param f file name of the new robot
     */
    public void addRobot(File f, GrxLinkItem parentLink) {
        try {
            GrxDebugUtil.println("Loading " + f.getCanonicalPath());
            ModelLoader mloader = ModelLoaderHelper.narrow(GrxCorbaUtil.getReference("ModelLoader")); //$NON-NLS-1$
            mloader._non_existent();
            BodyInfo bInfo = mloader.loadBodyInfo(f.getCanonicalPath());
            LinkInfo[] linkInfoList = bInfo.links();
            int numOfLink = links_.size();
            int numOfJoint = getDOF();
            Vector<String> sensorType = new Vector<String>();
            Vector<String>[] sensorNames = new Vector[GrxSensorItem.sensorType.length];
            for (int i = 0; i < GrxSensorItem.sensorType.length; i++) {
                sensorType.add(GrxSensorItem.sensorType[i]);
                sensorNames[i] = new Vector<String>();
                String[] names = getSensorNames(GrxSensorItem.sensorType[i]);
                if (names != null)
                    for (int j = 0; j < names.length; j++)
                        sensorNames[i].add(names[j]);
            }
            int rootIndex = -1;
            int jointCount = 0;
            for (int i = 0; i < linkInfoList.length; i++) {
                if (linkInfoList[i].parentIndex < 0) {
                    linkInfoList[i].parentIndex = (short) links_.indexOf(parentLink);
                    rootIndex = i + numOfLink;
                } else
                    linkInfoList[i].parentIndex += numOfLink;
                for (int j = 0; j < linkInfoList[i].childIndices.length; j++)
                    linkInfoList[i].childIndices[j] += numOfLink;
                if (linkInfoList[i].jointId >= 0) {
                    linkInfoList[i].jointId += numOfJoint;
                    jointCount++;
                }
                SensorInfo[] sensors = linkInfoList[i].sensors;
                for (int j = 0; j < sensors.length; j++) {
                    int type = sensorType.indexOf(sensors[j].type);
                    sensors[j].id += sensorNames[type].size();
                    String sensorName = sensors[j].name;
                    for (int k = 0; sensorNames[type].indexOf(sensorName) != -1; k++)
                        sensorName = sensors[j].name + "_" + k;
                    sensors[j].name = sensorName;
                }
                String linkName = linkInfoList[i].name;
                for (int j = 0; nameToLink_.get(linkName) != null; j++)
                    linkName = linkInfoList[i].name + "_" + j;
                GrxLinkItem link = new GrxLinkItem(linkName, manager_, this, linkInfoList[i]);
                nameToLink_.put(linkName, link);
            }
            createLink(rootIndex);
            jointToLink_ = new int[numOfJoint + jointCount];
            for (int i = 0; i < numOfJoint + jointCount; i++) {
                for (int j = 0; j < links_.size(); j++) {
                    if (links_.get(j).jointId_ == i) {
                        jointToLink_[i] = j;
                    }
                }
            }
            for (int i = numOfLink; i < numOfLink + linkInfoList.length; i++)
                manager_.itemChange(links_.get(i), GrxPluginManager.ADD_ITEM);

            shapes = bInfo.shapes();
            appearances = bInfo.appearances();
            materials = bInfo.materials();
            textures = bInfo.textures();

            for (int linkIndex = numOfLink; linkIndex < links_.size(); linkIndex++) {
                GrxLinkItem link = links_.get(linkIndex);
                for (int i = 0; i < link.children_.size(); i++) {
                    if (link.children_.get(i) instanceof GrxSegmentItem) {
                        GrxSegmentItem segment = (GrxSegmentItem) link.children_.get(i);
                        segment.addShape(segment.getTransform());
                    } else if (link.children_.get(i) instanceof GrxSensorItem) {
                        GrxSensorItem sensor = (GrxSensorItem) link.children_.get(i);
                        sensor.addShape(new Matrix4d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1));
                    } else if (link.children_.get(i) instanceof GrxHwcItem) {
                        GrxHwcItem hwc = (GrxHwcItem) link.children_.get(i);
                        hwc.addShape(new Matrix4d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1));
                    }
                }
            }
        } catch (Exception ex) {
            MessageDialog.openError(GrxUIPerspectiveFactory.getCurrentShell(),
                    MessageBundle.get("GrxModelItem.dialog.title.error"), //$NON-NLS-1$
                    MessageBundle.get("GrxModelItem.dialog.message.NoModelLoader"));
        }
    }

    /**
     * @brief
     */
    public class NormalRender {
        private LineArray nline = null;

        public NormalRender(GeometryArray geom, float scale, Matrix4d T) {

            Point3f[] vertices = new Point3f[geom.getVertexCount()];
            Vector3f[] normals = new Vector3f[geom.getVertexCount()];
            for (int i = 0; i < geom.getVertexCount(); i++) {
                vertices[i] = new Point3f();
                normals[i] = new Vector3f();
            }
            geom.getCoordinates(0, vertices);
            geom.getNormals(0, normals);
            Point3f[] nvertices = new Point3f[vertices.length * 2];
            int n = 0;
            for (int i = 0; i < vertices.length; i++) {

                T.transform(normals[i]);
                normals[i].normalize();
                T.transform(vertices[i]);

                nvertices[n++] = new Point3f(vertices[i]);
                nvertices[n++] = new Point3f(vertices[i].x + scale * normals[i].x,
                        vertices[i].y + scale * normals[i].y, vertices[i].z + scale * normals[i].z);
            }
            nline = new LineArray(nvertices.length, GeometryArray.COORDINATES);
            nline.setCoordinates(0, nvertices);
        }

        public LineArray getLineArray() {
            return nline;
        }
    }

    /**
     * @brief set transformation of the root joint and all joint values
     * @param lpos transformation of the root joint
     * @param q sequence of joint values
     */
    public void setCharacterPos(LinkPosition[] lpos, double[] q) {
        boolean isAllPosProvided = true;
        if (q != null) {
            for (int i = 0; i < jointToLink_.length; i++)
                links_.get(jointToLink_[i]).jointValue(q[i]);
        }
        for (int i = 0; i < links_.size(); i++) {
            if (lpos[i].p == null || lpos[i].R == null)
                isAllPosProvided = false;
            else {
                if (i == 0) {
                    links_.get(i).localTranslation(lpos[0].p);
                    links_.get(i).localRotation(lpos[0].R);
                }
                links_.get(i).absTransform(lpos[i].p, lpos[i].R);
            }
        }
        if (isAllPosProvided)
            updateCoM();
        else
            calcForwardKinematics();
    }

    /**
     * @brief set transformation of the root joint
     * @param pos position
     * @param rot rotation matrix
     */
    public void setTransformRoot(Vector3d pos, Matrix3d rot) {
        _setTransform(0, pos, rot);
    }

    /**
     * @brief set transformation of the root joint
     * @param pos position
     * @param rot rotation matrix
     */
    public void setTransformRoot(Transform3D tform) {
        Vector3d pos = new Vector3d();
        Matrix3d rot = new Matrix3d();
        tform.get(rot, pos);
        _setTransform(0, pos, rot);
    }

    /**
     * @brief set transformation of linkId th joint
     * @param linkId id of the link
     * @param pos position
     * @param rot rotation matrix
     */
    private void _setTransform(int linkId, Vector3d pos, Matrix3d rot) {
        GrxLinkItem link = links_.get(linkId);
        if (link != null)
            if (link.parent_ == null)
                link.setTransform(pos, rot);
    }

    /**
     * @brief set joint values
     * @param values joint values
     */
    public void setJointValues(final double[] values) {
        for (int j = 0; j < links_.size(); j++) {
            GrxLinkItem link = links_.get(j);
            if (link.jointId_ >= 0 && link.jointId_ < values.length) {
                link.jointValue(values[link.jointId_]);
            }
        }
    }

    /**
     * @brief modify joint value if it exceeds limit values
     */
    public void setJointValuesWithinLimit() {
        rootLink().setJointValuesWithinLimit();
    }

    /**
     * @brief update initial transformation property from current Transform3D
     */
    public void updateInitialTransformRoot() {
        Transform3D t3d = new Transform3D();
        Matrix3d m3d = new Matrix3d();
        Vector3d v3d = new Vector3d();

        getTransformGroupRoot().getTransform(t3d);
        t3d.get(m3d, v3d);
        setDblAry(rootLink().getName() + ".translation", new double[] { v3d.x, v3d.y, v3d.z }); //$NON-NLS-1$

        AxisAngle4d a4d = new AxisAngle4d();
        a4d.setMatrix(m3d);
        setDblAry(rootLink().getName() + ".rotation", new double[] { a4d.x, a4d.y, a4d.z, a4d.angle }); //$NON-NLS-1$
    }

    /**
     * @brief update joint value property from current joint value
     * @param link link
     */
    public void updateInitialJointValue(GrxLinkItem link) {
        if (link != null)
            setDbl(link.getName() + ".angle", link.jointValue_); //$NON-NLS-1$
    }

    /**
     * @breif update initial joint value properties from current joint values
     */
    public void updateInitialJointValues() {
        for (int i = 0; i < jointToLink_.length; i++) {
            GrxLinkItem l = links_.get(jointToLink_[i]);
            setDbl(l.getName() + ".angle", l.jointValue_); //$NON-NLS-1$
        }
    }

    /**
     * @brief compute forward kinematics
     */
    public void calcForwardKinematics() {
        rootLink().calcForwardKinematics();
        updateCoM();
    }

    /**
     * @brief update CoM and projected CoM positions
     */
    public void updateCoM() {
        if (switchCom_.getWhichChild() == Switch.CHILD_ALL || switchComZ0_.getWhichChild() == Switch.CHILD_ALL) {
            Vector3d v3d = new Vector3d();
            getCoM(v3d);
            Vector3d vz0 = new Vector3d(v3d);

            _globalToRoot(v3d);
            Transform3D t3d = new Transform3D();
            t3d.set(v3d);
            tgCom_.setTransform(t3d);

            vz0.z = 0.0;
            _globalToRoot(vz0);
            t3d.set(vz0);
            tgComZ0_.setTransform(t3d);
        }
    }

    /**
     * @brief convert global position into robot local
     * @param pos global position It is overwritten by robot local position
     */
    private void _globalToRoot(Vector3d pos) {
        Transform3D t3d = new Transform3D();
        getTransformGroupRoot().getTransform(t3d);
        Vector3d p = new Vector3d();
        t3d.get(p);
        t3d.invert();
        pos.sub(p);
        t3d.transform(pos);
    }

    /**
     * @brief compute center of mass
     * @param pos computed center of mass
     */
    public void getCoM(Vector3d pos) {
        pos.x = 0.0;
        pos.y = 0.0;
        pos.z = 0.0;
        double totalMass = 0.0;

        for (int i = 0; i < links_.size(); i++) {
            GrxLinkItem link = links_.get(i);
            totalMass += link.linkMass_;
            Vector3d absCom = link.absCoM();
            absCom.scale(link.linkMass_);
            pos.add(absCom);
        }
        pos.scale(1.0 / totalMass);
    }

    public List<GrxSensorItem> getSensors(String type) {
        List<GrxSensorItem> sensors = new ArrayList<GrxSensorItem>();
        rootLink().gatherSensors(type, sensors);
        if (sensors.size() > 0) {
            return sensors;
        } else {
            return null;
        }
    }

    public String[] getSensorNames(String type) {
        List<GrxSensorItem> l = getSensors(type);
        if (l == null)
            return null;

        String[] ret = new String[l.size()];
        for (int i = 0; i < ret.length; i++)
            ret[l.get(i).id_] = l.get(i).getName();
        return ret;
    }

    public TransformGroup getTransformGroupRoot() {
        return rootLink().tg_;
    }

    /**
     * @brief get transform of link in array form
     * @param link link
     * @return array. lenth = 12 = position(3)+rotation(9)
     */
    public double[] getTransformArray(GrxLinkItem link) {
        Transform3D t3d = new Transform3D();
        link.tg_.getTransform(t3d);
        Matrix3d mat = new Matrix3d();
        Vector3d vec = new Vector3d();
        t3d.get(mat, vec);

        double[] ret = new double[12];
        vec.get(ret);
        ret[3] = mat.m00;
        ret[4] = mat.m01;
        ret[5] = mat.m02;
        ret[6] = mat.m10;
        ret[7] = mat.m11;
        ret[8] = mat.m12;
        ret[9] = mat.m20;
        ret[10] = mat.m21;
        ret[11] = mat.m22;

        return ret;
    }

    public double[] getInitialTransformArray(GrxLinkItem link) {
        double[] ret = getTransformArray(link);

        double[] p = getDblAry(link.getName() + ".translation", null); //$NON-NLS-1$
        if (p != null && p.length == 3) {
            System.arraycopy(p, 0, ret, 0, 3);
        }

        double[] r = getDblAry(link.getName() + ".rotation", null); //$NON-NLS-1$
        if (r != null && r.length == 4) {
            Matrix3d mat = new Matrix3d();
            mat.set(new AxisAngle4d(r));
            ret[3] = mat.m00;
            ret[4] = mat.m01;
            ret[5] = mat.m02;
            ret[6] = mat.m10;
            ret[7] = mat.m11;
            ret[8] = mat.m12;
            ret[9] = mat.m20;
            ret[10] = mat.m21;
            ret[11] = mat.m22;
        }

        return ret;
    }

    public double[] getInitialVelocity(GrxLinkItem link) {
        double[] ret = { 0, 0, 0, 0, 0, 0 };
        double[] v = getDblAry(link.getName() + ".velocity", null);
        if (v != null && v.length == 3) {
            System.arraycopy(v, 0, ret, 0, 3);
        }
        double[] w = getDblAry(link.getName() + ".angularVelocity", null);
        if (w != null && w.length == 3) {
            System.arraycopy(w, 0, ret, 3, 3);
        }

        return ret;
    }

    public int getDOF() {
        if (jointToLink_ == null)
            return 0;
        return jointToLink_.length;
    }

    public String[] getJointNames() {
        String[] names = new String[jointToLink_.length];
        for (int i = 0; i < jointToLink_.length; i++)
            names[i] = links_.get(jointToLink_[i]).getName();
        return names;
    }

    public double[] getJointValues() {
        double[] vals = new double[jointToLink_.length];
        for (int i = 0; i < jointToLink_.length; i++)
            vals[i] = links_.get(jointToLink_[i]).jointValue_;
        return vals;
    }

    public double[] getInitialJointValues() {
        double[] ret = new double[jointToLink_.length];
        for (int i = 0; i < ret.length; i++) {
            GrxLinkItem l = links_.get(jointToLink_[i]);
            String jname = l.getName();
            ret[i] = getDbl(jname + ".angle", l.jointValue_); //$NON-NLS-1$
        }
        return ret;
    }

    public double[] getInitialJointVelocity() {
        double[] ret = new double[jointToLink_.length];
        for (int i = 0; i < ret.length; i++) {
            GrxLinkItem l = links_.get(jointToLink_[i]);
            String jname = l.getName();
            ret[i] = getDbl(jname + ".jointVelocity", 0.0); //$NON-NLS-1$
        }
        return ret;
    }

    /* public double[] getInitialJointMode() {
    double[] ret = new double[jointToLink_.length];
    for (int i=0; i<ret.length; i++) {
        String jname = links_.get(jointToLink_[i]).getName();
        String mode = getStr(jname+".mode", "Torque");
        ret[i] = mode.equals("HighGain") ? 1.0 : 0.0;
    }
    return ret;
     }*/
    public double[] getInitialJointMode() {
        double[] ret = new double[links_.size()];
        for (int i = 0; i < ret.length; i++) {
            String lname = links_.get(i).getName();
            String mode = getStr(lname + ".mode", "Torque"); //$NON-NLS-1$ //$NON-NLS-2$
            ret[i] = mode.equals("HighGain") ? 1.0 : 0.0; //$NON-NLS-1$
        }
        return ret;
    }

    public boolean isRobot() {
        return isRobot_;
    }

    public void setSelected(boolean b) {
        super.setSelected(b);
        /*
        if (!b) {
        bgRoot_.detach();
        for (int i=0; i<cameraList_.size(); i++)
            cameraList_.get(i).getBranchGroup().detach();
        }
        */
    }

    /**
     * @brief set/unset focus on this item
     * 
     * When this item is focused, its bounding box is displayed.
     * @param true to focus, false to unfocus
     */
    public void setFocused(boolean b) {
        if (b)
            resizeBoundingBox();
        switchBb_.setWhichChild(b ? Switch.CHILD_ALL : Switch.CHILD_NONE);
    }

    /**
     * delete this item
     */
    public void delete() {
        super.delete();
        Iterator<Camera_impl> it = cameraList_.iterator();
        while (it.hasNext())
            it.next().destroy();
        if (bgRoot_.isLive())
            bgRoot_.detach();
        Map<?, ?> m = manager_.pluginMap_.get((GrxCollisionPairItem.class));
        GrxCollisionPairItem[] collisionPairItems = m.values().toArray(new GrxCollisionPairItem[0]);
        for (int i = 0; i < collisionPairItems.length; i++) {
            GrxCollisionPairItem item = (GrxCollisionPairItem) collisionPairItems[i];
            String name = getName();
            if (name.equals(item.getStr("objectName1", ""))) { //$NON-NLS-1$ //$NON-NLS-2$
                item.delete();
            } else if (name.equals(item.getStr("objectName2", ""))) { //$NON-NLS-1$ //$NON-NLS-2$
                item.delete();
            }
        }
        m = manager_.pluginMap_.get((GrxExtraJointItem.class));
        GrxExtraJointItem[] extraJointItems = m.values().toArray(new GrxExtraJointItem[0]);
        for (int i = 0; i < extraJointItems.length; i++) {
            GrxExtraJointItem item = extraJointItems[i];
            String name = getName();
            if (name.equals(item.getStr("object1Name", ""))) { //$NON-NLS-1$ //$NON-NLS-2$
                item.delete();
            } else if (name.equals(item.getStr("object2Name", ""))) { //$NON-NLS-1$ //$NON-NLS-2$
                item.delete();
            }
        }
        GrxLinkItem root = rootLink();
        if (root != null)
            root.delete();
    }

    /**
     * @brief resize bounding box which covers the whole body
     */
    public void resizeBoundingBox() {
        SceneGraphModifier modifier = SceneGraphModifier.getInstance();
        modifier.init_ = true;
        modifier.mode_ = SceneGraphModifier.RESIZE_BOUNDS;

        // ?Root?TransformGroup?
        TransformGroup tg = getTransformGroupRoot();
        Transform3D t3dLocal = new Transform3D();
        tg.getTransform(t3dLocal);
        t3dLocal.invert();
        for (int i = 0; i < links_.size(); i++) {
            modifier._calcUpperLower(links_.get(i).tg_, t3dLocal);
        }
        Shape3D shapeNode = (Shape3D) switchBb_.getChild(0);
        Geometry gm = (Geometry) shapeNode.getGeometry(0);

        Point3f[] p3fW = modifier._makePoints();
        if (gm instanceof QuadArray) {
            QuadArray qa = (QuadArray) gm;
            qa.setCoordinates(0, p3fW); // 
        }
    }

    /**
     * @brief set visibility of CoM
     * @param b true to make it visible, false otherwise
     */
    public void setVisibleCoM(boolean b) {
        if (isRobot()) {
            switchCom_.setWhichChild(b ? Switch.CHILD_ALL : Switch.CHILD_NONE);
            calcForwardKinematics();
        } else {
            switchCom_.setWhichChild(Switch.CHILD_NONE);
        }
    }

    /**
     * @brief set visibility of CoM projected on the floor
     * @param b true to make it visible, false otherwise
     */
    public void setVisibleCoMonFloor(boolean b) {
        if (isRobot()) {
            switchComZ0_.setWhichChild(b ? Switch.CHILD_ALL : Switch.CHILD_NONE);
            calcForwardKinematics();
        } else {
            switchComZ0_.setWhichChild(Switch.CHILD_NONE);
        }
    }

    /**
     * @brief switch display mode between fill and line
     * @param b true to switch to line mode, false otherwise
     */
    public void setWireFrame(boolean b) {
        setWireFrame(b, bgRoot_);
    }

    /**
     * @brief switch display mode between fill and line
     * @param b true to switch to line mode, false otherwise
     * @param node top of subtree to be processed
     */
    public void setWireFrame(boolean b, Node node) {
        if (node instanceof Switch) {
            return;
        } else if (node instanceof Group) {
            Group g = (Group) node;
            for (int i = 0; i < g.numChildren(); i++)
                setWireFrame(b, g.getChild(i));

        } else if (node instanceof Link) {
            Link l = (Link) node;
            SharedGroup sg = l.getSharedGroup();
            for (int i = 0; i < sg.numChildren(); i++)
                setWireFrame(b, sg.getChild(i));

        } else if (node instanceof Shape3D) {
            Shape3D s3d = (Shape3D) node;
            Appearance app = s3d.getAppearance();
            if (app != null) {
                PolygonAttributes pa = app.getPolygonAttributes();
                if (pa != null) {
                    if (b) {
                        pa.setPolygonMode(PolygonAttributes.POLYGON_LINE);
                    } else {
                        pa.setPolygonMode(PolygonAttributes.POLYGON_FILL);
                    }
                }
            }
        }
    }

    public void setVisibleAABB(boolean b) {
        Iterator<GrxLinkItem> it = links_.iterator();
        while (it.hasNext())
            it.next().setVisibleAABB(b);
    }

    /**
     * @brief 
     * @param b
     */
    public void setTransparencyMode(boolean b) {
        setTransparencyMode(b, bgRoot_);
    }

    /**
     * @brief
     * @param b
     * @param node
     */
    private void setTransparencyMode(boolean b, Node node) {
        if (node instanceof Switch) {
            return;
        } else if (node instanceof Group) {
            Group g = (Group) node;
            for (int i = 0; i < g.numChildren(); i++)
                setTransparencyMode(b, g.getChild(i));

        } else if (node instanceof Link) {
            Link l = (Link) node;
            SharedGroup sg = l.getSharedGroup();
            for (int i = 0; i < sg.numChildren(); i++)
                setTransparencyMode(b, sg.getChild(i));

        } else if (node instanceof Shape3D) {
            Shape3D s3d = (Shape3D) node;
            Appearance app = s3d.getAppearance();
            if (app != null) {
                TransparencyAttributes ta = app.getTransparencyAttributes();
                if (ta != null) {
                    if (b) {
                        ta.setTransparency(0.5f);
                        ta.setTransparencyMode(TransparencyAttributes.FASTEST);
                    } else {
                        ta.setTransparency(0f);
                        ta.setTransparencyMode(TransparencyAttributes.NONE);
                    }
                }
            }
        }
    }

    /**
     * @brief get sequence of cameras
     * @return sequence of cameras
     */
    public List<Camera_impl> getCameraSequence() {
        return cameraList_;
    }

    /**
     * @brief set color of joint
     * @param jid joint id
     * @param color color
     */
    public void setJointColor(int jid, java.awt.Color color) {
        GrxLinkItem l = links_.get(jointToLink_[jid]);
        if (l != null)
            l.setColor(color);
    }

    /* this method is disabled to hide paste menu 
    public void paste(String clipVal){
        
    Clipboard clp = Toolkit.getDefaultToolkit().getSystemClipboard();
    Transferable data = clp.getContents(null);
        
    String strClip = "";
        
    if (data == null || !data.isDataFlavorSupported(DataFlavor.stringFlavor)){
        strClip = "??????";
    } else {
        try {
            strClip = (String)data.getTransferData( DataFlavor.stringFlavor );
        } catch(Exception e) {
            GrxDebugUtil.printErr("GrxModelItem.paste: " , e);
        }
    }
    }
    */

    /**
     * @brief Override clone method
     * @return GrxModelItem
     */
    public GrxModelItem clone() {
        GrxModelItem ret = (GrxModelItem) super.clone();
        ret.bInfo_ = (BodyInfo) bInfo_._duplicate();
        //ret.bgRoot_ = (BodyInfo)bgRoot_.cloneTree();

        ret.links_ = new Vector<GrxLinkItem>(links_);
        //ret.activeLink_ = activeLink_.clone();
        /*       
           Deep copy suspension list
            
            public BodyInfo bInfo_;
            
            public BranchGroup bgRoot_ = new BranchGroup();
            public Vector<GrxLinkItem> links_ = new Vector<GrxLinkItem>();
            public GrxLinkItem activeLink_;
            private int[] jointToLink_; // length = joint number
            private final Map<String, GrxLinkItem> linkMap_ = new HashMap<String, GrxLinkItem>();
            private final Vector<Shape3D> shapeVector_ = new Vector<Shape3D>();
            // sensor type name -> list of sensors
            private final Map<String, List<GrxSensorItem>> sensorMap_ = new HashMap<String, List<GrxSensorItem>>();
            // list of cameras
            private List<Camera_impl> cameraList_ = new ArrayList<Camera_impl>();
            
            private Switch switchCom_;
            private TransformGroup tgCom_;
            private Switch switchComZ0_;
            private TransformGroup tgComZ0_;
            
            // temporary variables for computation
            private Transform3D t3d_ = new Transform3D();
            private Vector3d v3d_ = new Vector3d();
        */

        return ret;
    }

    /**
     * @brief get link from name
     * @param name name of the link
     * @return link if found, null otherwise
     */
    public GrxLinkItem getLink(String name) {
        return nameToLink_.get(name);
    }

    private BodyInfo getBodyInfoFromModelLoader() {
        short[] depth = new short[links_.size()];
        for (int i = 0; i < links_.size(); i++)
            depth[i] = links_.get(i).getInt("NumOfAABB", 1).shortValue();
        try {
            ModelLoader mloader = ModelLoaderHelper.narrow(GrxCorbaUtil.getReference("ModelLoader")); //$NON-NLS-1$
            mloader._non_existent();
            ModelLoadOption option = new ModelLoadOption();
            option.readImage = false;
            option.AABBtype = AABBdataType.AABB_NUM;
            option.AABBdata = depth;

            return mloader.getBodyInfoEx(getURL(false), option);
        } catch (Exception e) {
            MessageDialog.openError(GrxUIPerspectiveFactory.getCurrentShell(),
                    MessageBundle.get("GrxModelItem.dialog.title.error"), //$NON-NLS-1$
                    MessageBundle.get("GrxModelItem.dialog.message.NoModelLoader"));
            return null;
        }
    }

    private void makeAABB(BodyInfo binfo) {
        bInfo_ = binfo;

        LinkInfo[] links = bInfo_.links();
        shapes = bInfo_.shapes();
        appearances = bInfo_.appearances();
        materials = bInfo_.materials();
        textures = bInfo_.textures();

        int numLinks = links.length;
        for (int i = 0; i < numLinks; i++) {
            links_.get(i).clearAABB();
            TransformedShapeIndex[] tsi = links[i].shapeIndices;
            for (int j = 0; j < tsi.length; j++) {
                links_.get(i).makeAABB(shapes[tsi[j].shapeIndex], tsi[j].transformMatrix);
            }
        }
        notifyObservers("BodyInfoChange");
    }

    public List<GrxModelItem> getSameUrlModels() {
        List<GrxModelItem> models = manager_.<GrxModelItem>getSelectedItemList(GrxModelItem.class);
        Iterator<GrxModelItem> it = models.iterator();
        while (it.hasNext()) {
            GrxModelItem model = it.next();
            if (!model.getURL(true).equals(getURL(true)) || model == this)
                it.remove();
        }
        return models;
    }

    public void makeAABBforSameUrlModels() {
        BodyInfo bodyInfo = getBodyInfoFromModelLoader();
        makeAABB(bodyInfo);
        List<GrxModelItem> sameModels = getSameUrlModels();
        Iterator<GrxModelItem> it = sameModels.iterator();
        while (it.hasNext()) {
            GrxModelItem _model = it.next();
            for (int i = 0; i < links_.size(); i++) {
                String value = links_.get(i).getStr("NumOfAABB");
                _model.nameToLink_.get(links_.get(i).getName()).setProperty("NumOfAABB", value);
                _model.setProperty(links_.get(i).getName() + ".NumOfAABB", value);
            }
            _model.makeAABB(bodyInfo);
        }
    }

    /**
     * @brief rename this Model
     * @param newName new name
     */
    public void rename(String newName) {
        String oldName = getName();

        super.rename(newName);

        OrderedHashMap mcoll = manager_.pluginMap_.get(GrxCollisionPairItem.class);
        if (mcoll != null) {
            Iterator it = mcoll.values().iterator();
            while (it.hasNext()) {
                GrxCollisionPairItem ci = (GrxCollisionPairItem) it.next();
                if (oldName.equals(ci.getProperty("objectName1")))
                    ci.setProperty("objectName1", newName);

                if (oldName.equals(ci.getProperty("objectName2")))
                    ci.setProperty("objectName2", newName);
            }
        }
        mcoll = manager_.pluginMap_.get(GrxExtraJointItem.class);
        if (mcoll != null) {
            Iterator it = mcoll.values().iterator();
            while (it.hasNext()) {
                GrxExtraJointItem extraJoint = (GrxExtraJointItem) it.next();
                if (oldName.equals(extraJoint.getProperty("object1Name")))
                    extraJoint.setProperty("object1Name", newName);

                if (oldName.equals(extraJoint.getProperty("object2Name")))
                    extraJoint.setProperty("object2Name", newName);
            }
        }
    }

    @Override
    public ValueEditType GetValueEditType(String key) {
        if (key.matches(".+\\.mode")) {
            return new ValueEditCombo(modeComboItem_);
        } else if (key.equals("isRobot")) {
            return new ValueEditCombo(booleanComboItem_);
        }
        return super.GetValueEditType(key);
    }

    public void removeExtraJoint(GrxExtraJointItem extraJoint) {
        extraJoints_.remove(extraJoint);
        notifyModified();
    }

    private void addExtraJoint(String name) {
        GrxExtraJointItem extraJoint = new GrxExtraJointItem(name, manager_, this, null);
        this.extraJoints_.add(extraJoint);
        notifyModified();
        manager_.itemChange(extraJoint, GrxPluginManager.ADD_ITEM);
    }
}