2 * typical bone information
4 * License : The MIT License
5 * Copyright(c) 2011 MikuToga Partners
8 package jp.sfjp.mikutoga.typical;
10 import java.io.IOException;
11 import java.io.InputStream;
12 import java.util.Collections;
13 import java.util.LinkedList;
14 import java.util.List;
15 import javax.xml.parsers.ParserConfigurationException;
16 import org.w3c.dom.Element;
17 import org.w3c.dom.NodeList;
18 import org.xml.sax.SAXException;
23 * <p>各ボーン情報はひとつ以上のプライマリ名(≒日本語名)と
24 * ゼロ個以上のグローバル名(≒英語名)を持つ。
28 * <p>和英対訳はMMD Ver7.39の同梱モデルにほぼ準拠。
30 public final class TypicalBone extends I18nAlias {
32 private static final Class<?> THISCLASS = TypicalBone.class;
33 private static final String BONE_XML = "resources/typicalBone.xml";
35 private static final String ELEM_BONE = "bone";
36 private static final String ELEM_ROOT = "root";
37 private static final String ELEM_PRIMARY = "primary";
38 private static final String ELEM_GLOBAL = "global";
39 private static final String ATTR_NAME = "name";
41 private static final List<TypicalBone> BONE_LIST =
42 new LinkedList<TypicalBone>();
43 private static final AliasMap<TypicalBone> BONE_ALIAS_MAP =
44 new AliasMap<TypicalBone>();
46 private static final List<TypicalBone> BONE_UNMODLIST =
47 Collections.unmodifiableList(BONE_LIST);
50 InputStream is = THISCLASS.getResourceAsStream(BONE_XML);
54 top = I18nAlias.loadXml(is);
55 }catch(ParserConfigurationException e){
56 throw new ExceptionInInitializerError(e);
57 }catch(SAXException e){
58 throw new ExceptionInInitializerError(e);
59 }catch(IOException e){
60 throw new ExceptionInInitializerError(e);
69 private boolean isRoot;
76 * 状況に応じて伸長する連結リストが用意される。
78 * @param primaryNum プライマリ名初期数。
79 * @param globalNum グローバル名初期数。
81 private TypicalBone(int primaryNum, int globalNum){
82 super(primaryNum, globalNum);
83 assert this.getClass() == THISCLASS;
92 private static void parse(Element top) {
93 NodeList boneList = top.getElementsByTagName(ELEM_BONE);
94 int boneNo = boneList.getLength();
95 for(int idx = 0; idx < boneNo; idx++){
96 Element boneElem = (Element) boneList.item(idx);
97 TypicalBone typBone = parseBone(boneElem);
98 BONE_LIST.add(typBone);
99 BONE_ALIAS_MAP.addAlias(typBone);
107 * @param boneElem bone要素
110 private static TypicalBone parseBone(Element boneElem){
111 NodeList primaryNodes = boneElem.getElementsByTagName(ELEM_PRIMARY);
112 NodeList globalNodes = boneElem.getElementsByTagName(ELEM_GLOBAL);
113 int primaryNo = primaryNodes.getLength();
114 int globalNo = globalNodes.getLength();
116 assert primaryNo > 0;
118 TypicalBone bone = new TypicalBone(primaryNo, globalNo);
120 for(int idx = 0; idx < primaryNo; idx++){
121 Element primaryElem = (Element) primaryNodes.item(idx);
122 String name = primaryElem.getAttribute(ATTR_NAME);
123 bone.addPrimaryName(name);
126 for(int idx = 0; idx < globalNo; idx++){
127 Element globalElem = (Element) globalNodes.item(idx);
128 String name = globalElem.getAttribute(ATTR_NAME);
129 bone.addGlobalName(name);
132 NodeList rootNodes = boneElem.getElementsByTagName(ELEM_ROOT);
133 if(rootNodes.getLength() > 0){
147 private static void numbering(){
149 for(TypicalBone bone : BONE_LIST){
150 bone.setOrderNo(order++);
160 public static List<TypicalBone> getTypicalBoneList(){
161 return BONE_UNMODLIST;
165 * プライマリ名の合致するボーン情報を返す。
166 * NFKCで正規化されたプライマリ名で検索される。
167 * @param primaryName プライマリ名
168 * @return モーフ情報。見つからなければnull
170 public static TypicalBone findWithPrimary(String primaryName){
171 TypicalBone result = BONE_ALIAS_MAP.getAliasByPrimary(primaryName);
176 * グローバル名の合致するボーン情報を返す。
177 * NFKCで正規化されたグローバル名で検索される。
178 * @param globalName グローバル名
179 * @return モーフ情報。見つからなければnull
181 public static TypicalBone findWithGlobal(String globalName){
182 TypicalBone result = BONE_ALIAS_MAP.getAliasByGlobal(globalName);
187 * プライマリ名をグローバル名に変換する。
188 * @param primaryName プライマリ名
189 * @return グローバル名。見つからなければnull
191 public static String primary2global(String primaryName){
192 String globalName = BONE_ALIAS_MAP.primary2global(primaryName);
197 * グローバル名をプライマリ名へ変換する。
198 * @param globalName グローバル名
199 * @return プライマリ名。見つからなければnull
201 public static String global2primary(String globalName){
202 String primaryName = BONE_ALIAS_MAP.global2primary(globalName);
208 * このボーンが親を持たないルートボーンとして扱われる慣習なのか
211 * <p>※「全親」ボーンに関する慣習は無視される。
213 * @return 親を持たなければtrue
215 public boolean isRoot(){