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 =
43 private static final AliasMap<TypicalBone> BONE_ALIAS_MAP =
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 | SAXException | IOException e){
56 throw new ExceptionInInitializerError(e);
65 private boolean isRoot;
72 * 状況に応じて伸長する連結リストが用意される。
74 * @param primaryNum プライマリ名初期数。
75 * @param globalNum グローバル名初期数。
77 private TypicalBone(int primaryNum, int globalNum){
78 super(primaryNum, globalNum);
79 assert this.getClass() == THISCLASS;
88 private static void parse(Element top) {
89 NodeList boneList = top.getElementsByTagName(ELEM_BONE);
90 int boneNo = boneList.getLength();
91 for(int idx = 0; idx < boneNo; idx++){
92 Element boneElem = (Element) boneList.item(idx);
93 TypicalBone typBone = parseBone(boneElem);
94 BONE_LIST.add(typBone);
95 BONE_ALIAS_MAP.addAlias(typBone);
103 * @param boneElem bone要素
106 private static TypicalBone parseBone(Element boneElem){
107 NodeList primaryNodes = boneElem.getElementsByTagName(ELEM_PRIMARY);
108 NodeList globalNodes = boneElem.getElementsByTagName(ELEM_GLOBAL);
109 int primaryNo = primaryNodes.getLength();
110 int globalNo = globalNodes.getLength();
112 assert primaryNo > 0;
114 TypicalBone bone = new TypicalBone(primaryNo, globalNo);
116 for(int idx = 0; idx < primaryNo; idx++){
117 Element primaryElem = (Element) primaryNodes.item(idx);
118 String name = primaryElem.getAttribute(ATTR_NAME);
119 bone.addPrimaryName(name);
122 for(int idx = 0; idx < globalNo; idx++){
123 Element globalElem = (Element) globalNodes.item(idx);
124 String name = globalElem.getAttribute(ATTR_NAME);
125 bone.addGlobalName(name);
128 NodeList rootNodes = boneElem.getElementsByTagName(ELEM_ROOT);
129 if(rootNodes.getLength() > 0){
143 private static void numbering(){
145 for(TypicalBone bone : BONE_LIST){
146 bone.setOrderNo(order++);
156 public static List<TypicalBone> getTypicalBoneList(){
157 return BONE_UNMODLIST;
161 * プライマリ名の合致するボーン情報を返す。
162 * NFKCで正規化されたプライマリ名で検索される。
163 * @param primaryName プライマリ名
164 * @return モーフ情報。見つからなければnull
166 public static TypicalBone findWithPrimary(String primaryName){
167 TypicalBone result = BONE_ALIAS_MAP.getAliasByPrimary(primaryName);
172 * グローバル名の合致するボーン情報を返す。
173 * NFKCで正規化されたグローバル名で検索される。
174 * @param globalName グローバル名
175 * @return モーフ情報。見つからなければnull
177 public static TypicalBone findWithGlobal(String globalName){
178 TypicalBone result = BONE_ALIAS_MAP.getAliasByGlobal(globalName);
183 * プライマリ名をグローバル名に変換する。
184 * @param primaryName プライマリ名
185 * @return グローバル名。見つからなければnull
187 public static String primary2global(String primaryName){
188 String globalName = BONE_ALIAS_MAP.primary2global(primaryName);
193 * グローバル名をプライマリ名へ変換する。
194 * @param globalName グローバル名
195 * @return プライマリ名。見つからなければnull
197 public static String global2primary(String globalName){
198 String primaryName = BONE_ALIAS_MAP.global2primary(globalName);
204 * このボーンが親を持たないルートボーンとして扱われる慣習なのか
207 * <p>※「全親」ボーンに関する慣習は無視される。
209 * @return 親を持たなければtrue
211 public boolean isRoot(){