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;
22 * <p>各ボーン情報はひとつ以上のプライマリ名(≒日本語名)と
23 * ゼロ個以上のグローバル名(≒英語名)を持つ。
25 * <p>和英対訳はMMD Ver7.39の同梱モデルにほぼ準拠。
27 public final class TypicalBone extends I18nAlias {
29 private static final Class<?> THISCLASS = TypicalBone.class;
30 private static final String BONE_XML = "resources/typicalBone.xml";
32 private static final String ELEM_BONE = "bone";
33 private static final String ELEM_ROOT = "root";
34 private static final String ELEM_PRIMARY = "primary";
35 private static final String ELEM_GLOBAL = "global";
36 private static final String ATTR_NAME = "name";
38 private static final List<TypicalBone> BONE_LIST =
39 new LinkedList<TypicalBone>();
40 private static final AliasMap<TypicalBone> BONE_ALIAS_MAP =
41 new AliasMap<TypicalBone>();
43 private static final List<TypicalBone> BONE_UNMODLIST =
44 Collections.unmodifiableList(BONE_LIST);
47 InputStream is = THISCLASS.getResourceAsStream(BONE_XML);
51 top = I18nAlias.loadXml(is);
52 }catch(ParserConfigurationException e){
53 throw new ExceptionInInitializerError(e);
54 }catch(SAXException e){
55 throw new ExceptionInInitializerError(e);
56 }catch(IOException e){
57 throw new ExceptionInInitializerError(e);
66 private boolean isRoot;
72 * 状況に応じて伸長する連結リストが用意される。
73 * @param primaryNum プライマリ名初期数。
74 * @param globalNum グローバル名初期数。
76 private TypicalBone(int primaryNum, int globalNum){
77 super(primaryNum, globalNum);
78 assert this.getClass() == THISCLASS;
87 private static void parse(Element top) {
88 NodeList boneList = top.getElementsByTagName(ELEM_BONE);
89 int boneNo = boneList.getLength();
90 for(int idx = 0; idx < boneNo; idx++){
91 Element boneElem = (Element) boneList.item(idx);
92 TypicalBone typBone = parseBone(boneElem);
93 BONE_LIST.add(typBone);
94 BONE_ALIAS_MAP.addAlias(typBone);
102 * @param boneElem bone要素
105 private static TypicalBone parseBone(Element boneElem){
106 NodeList primaryNodes = boneElem.getElementsByTagName(ELEM_PRIMARY);
107 NodeList globalNodes = boneElem.getElementsByTagName(ELEM_GLOBAL);
108 int primaryNo = primaryNodes.getLength();
109 int globalNo = globalNodes.getLength();
111 assert primaryNo > 0;
113 TypicalBone bone = new TypicalBone(primaryNo, globalNo);
115 for(int idx = 0; idx < primaryNo; idx++){
116 Element primaryElem = (Element) primaryNodes.item(idx);
117 String name = primaryElem.getAttribute(ATTR_NAME);
118 bone.addPrimaryName(name);
121 for(int idx = 0; idx < globalNo; idx++){
122 Element globalElem = (Element) globalNodes.item(idx);
123 String name = globalElem.getAttribute(ATTR_NAME);
124 bone.addGlobalName(name);
127 NodeList rootNodes = boneElem.getElementsByTagName(ELEM_ROOT);
128 if(rootNodes.getLength() > 0){
141 private static void numbering(){
143 for(TypicalBone bone : BONE_LIST){
144 bone.setOrderNo(order++);
154 public static List<TypicalBone> getTypicalBoneList(){
155 return BONE_UNMODLIST;
159 * プライマリ名の合致するボーン情報を返す。
160 * NFKCで正規化されたプライマリ名で検索される。
161 * @param primaryName プライマリ名
162 * @return モーフ情報。見つからなければnull
164 public static TypicalBone findWithPrimary(String primaryName){
165 TypicalBone result = BONE_ALIAS_MAP.getAliasByPrimary(primaryName);
170 * グローバル名の合致するボーン情報を返す。
171 * NFKCで正規化されたグローバル名で検索される。
172 * @param globalName グローバル名
173 * @return モーフ情報。見つからなければnull
175 public static TypicalBone findWithGlobal(String globalName){
176 TypicalBone result = BONE_ALIAS_MAP.getAliasByGlobal(globalName);
181 * プライマリ名をグローバル名に変換する。
182 * @param primaryName プライマリ名
183 * @return グローバル名。見つからなければnull
185 public static String primary2global(String primaryName){
186 String globalName = BONE_ALIAS_MAP.primary2global(primaryName);
191 * グローバル名をプライマリ名へ変換する。
192 * @param globalName グローバル名
193 * @return プライマリ名。見つからなければnull
195 public static String global2primary(String globalName){
196 String primaryName = BONE_ALIAS_MAP.global2primary(globalName);
202 * このボーンが親を持たないルートボーンとして扱われる慣習なのか
204 * <p>※「全親」ボーンに関する慣習は無視される。
205 * @return 親を持たなければtrue
207 public boolean isRoot(){