|
funkalicious 0.1
|
00001 /* 00002 * matdb: generic materials database information. 00003 00004 00005 00006 Copyright (C) 2009 Joseph Pingenot 00007 00008 This program is free software: you can redistribute it and/or modify 00009 it under the terms of the GNU Affero General Public License as published by 00010 the Free Software Foundation, either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 This program is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU Affero General Public License for more details. 00017 00018 You should have received a copy of the GNU Affero General Public License 00019 along with this program. If not, see <http://www.gnu.org/licenses/>. 00020 00021 */ 00022 00023 #include <stdio.h> 00024 #include <stdlib.h> 00025 #include <math.h> 00026 #include <glib-2.0/glib.h> 00027 #include <libdotcode/matdb.h> 00028 00029 00030 static void print_property(gpointer key, gpointer value, gpointer user_data) { 00031 fprintf(stderr, "\t\t%s=%g:\n", (char*)key, *(double*)value); 00032 } 00033 static void print_inner_bowing(gpointer key, gpointer value, gpointer user_data) { 00034 struct matdb_bowing *bowing = (struct matdb_bowing*)value; 00035 fprintf(stderr, "\tbowing %s:%s[%s:%s]:\n", bowing->from->str, bowing->to->str, (char*)user_data, (char*)key); 00036 g_hash_table_foreach(bowing->properties, &print_property, NULL); 00037 } 00038 static void print_material(gpointer key, gpointer value, gpointer user_data) { 00039 struct matdb_material *mat = (struct matdb_material*)value; 00040 fprintf(stderr, "\tmaterial %s(%s):\n", mat->name->str, (char*)key); 00041 g_hash_table_foreach(mat->properties, &print_property, NULL); 00042 } 00043 static void print_bowing(gpointer key, gpointer value, gpointer user_data) { 00044 GHashTable *ht = (GHashTable*)value; 00045 g_hash_table_foreach(ht, &print_inner_bowing, key); 00046 } 00047 00048 void print_matdb(const struct matdb *mdb) { 00049 fprintf(stderr, "matdb:\n"); 00050 g_hash_table_foreach(mdb->materials, &print_material, NULL); 00051 g_hash_table_foreach(mdb->bowings, &print_bowing, NULL); 00052 } 00053 00054 void destroy_material_gpointer(gpointer data) { 00055 destroy_material((struct matdb_material *)data); 00056 } 00057 void destroy_bowing_gpointer(gpointer data) { 00058 destroy_bowing((struct matdb_bowing *)data); 00059 } 00060 void destroy_material(struct matdb_material *mat) { 00061 #ifdef DEBUG 00062 fprintf(stderr, "destroy_material\n"); 00063 #endif 00064 g_string_free(mat->name, TRUE); 00065 g_hash_table_unref(mat->properties); 00066 free(mat); 00067 } 00068 void destroy_bowing(struct matdb_bowing *bow) { 00069 #ifdef DEBUG 00070 fprintf(stderr, "destroy_bowing\n"); 00071 #endif 00072 g_string_free(bow->from, TRUE); 00073 g_string_free(bow->to, TRUE); 00074 g_hash_table_unref(bow->properties); 00075 free(bow); 00076 } 00077 00078 double* new_double(double d) {double* D = (double*)malloc(sizeof(double)); *D = d; return D;} 00079 00080 struct foreach_datum { 00081 GHashTable *new_table; 00082 GHashTable *mat2_ppts; 00083 GHashTable *bowings; 00084 char* mat1; 00085 char* mat2; 00086 double x; 00087 }; 00088 00089 /*Bowing definition from Vurgaftman*/ 00090 double interpolate_with_bowing(double mat1, double mat2, double bow, double x) { 00091 return x*mat1 + (1-x)*mat2 - x*(1-x)*bow; 00092 } 00093 00094 double interpolate_without_bowing(double mat1, double mat2, double x) { 00095 return x*mat1 + (1-x)*mat2; 00096 } 00097 00098 void clone_each_property(gpointer key, gpointer value, gpointer data) { 00099 char* ppt = (char*)key; 00100 double* val1 = (double*)value; 00101 struct foreach_datum* fd = (struct foreach_datum*)data; 00102 double* val2; 00103 double* bow; 00104 double result; 00105 if(fd->mat2_ppts != NULL) { 00106 val2 = (double*)g_hash_table_lookup(fd->mat2_ppts, ppt); 00107 if(val2 == NULL) { 00108 fprintf(stderr, "matdb.c::clone_each_property: WARNING material %s in material %s is not set in %s; skipping for their alloy.\n", ppt, fd->mat1, fd->mat2); 00109 return; 00110 }else{ 00111 if((bow = (double*)g_hash_table_lookup(fd->bowings, ppt)) == NULL) { 00112 result = interpolate_without_bowing(*val1, *val2, fd->x); 00113 }else{ 00114 result = interpolate_with_bowing(*val1, *val2, *bow, fd->x); 00115 } 00116 } 00117 } else { 00118 val2=NULL; 00119 result = *val1; 00120 } 00121 g_hash_table_insert(fd->new_table, g_strdup(ppt), new_double(result)); 00122 } 00123 00124 GHashTable* get_material(const struct matdb* matdb, const char* mat1, const char* mat2, double x) { 00125 if((x < 0) || (x>1)) { 00126 fprintf(stderr, "matdb::get_material: material %s(%f)%s doesn't exist: x not in range [0, 1]\n", mat1, x, mat2); 00127 return NULL; 00128 } 00129 if(((!(fabs(x-1.0)) < 1e-8) && (mat2 == NULL))){ 00130 fprintf(stderr, "matdb::get_material: material %s(%f)%s doesn't exist: x!=1 and mat2 is NULL\n", mat1, x, mat2); 00131 return NULL; 00132 } 00133 struct foreach_datum fd; 00134 void* rv; 00135 rv = g_hash_table_lookup(matdb->materials, mat1); 00136 GHashTable *ppts1 = NULL; 00137 if(rv == NULL) { 00138 fprintf(stderr, "matdb::get_material: unable to find material %s in materials database!\n", mat1); 00139 return NULL; 00140 } else { 00141 ppts1 = ((struct matdb_material*)rv)->properties; 00142 } 00143 if(mat2 == NULL) { 00144 fd.mat2_ppts = NULL; 00145 } else { 00146 rv = g_hash_table_lookup(matdb->materials, mat2); 00147 if(rv == NULL) { 00148 fprintf(stderr, "matdb::get_material: unable to find material %s in materials database!\n", mat2); 00149 return NULL; 00150 } 00151 fd.mat2_ppts = ((struct matdb_material*)rv)->properties; 00152 } 00153 fd.new_table = g_hash_table_new_full(g_str_hash, g_str_equal, free, free); 00154 /*We cast away the const-ness; we need to store these in a struct.*/ 00155 fd.mat1 = (char*)mat1; 00156 fd.mat2 = (char*)mat2; 00157 fd.x = x; 00158 rv = NULL; 00159 /*Look up and set bowings, if they exist.*/ 00160 if(mat2 != NULL) { 00161 GHashTable *ht = (GHashTable*)g_hash_table_lookup(matdb->bowings, mat1); 00162 if(ht != NULL) { 00163 rv = g_hash_table_lookup(ht, mat2); 00164 if(rv != NULL) { 00165 fd.bowings = ((struct matdb_bowing*)rv)->properties; 00166 }else{ 00167 fd.bowings = NULL; 00168 } 00169 }else{ 00170 fd.bowings = NULL; 00171 } 00172 }else{ 00173 fd.bowings = NULL; 00174 } 00175 g_hash_table_foreach(ppts1, clone_each_property, &fd); 00176 /*Everything else is someone else's pointers, so we don't have to free anything.*/ 00177 return fd.new_table; 00178 } 00179 00180 double get_property1(const struct matdb* matdb, const char* ppt, const char* mat, int* err) { 00181 void* rv; 00182 GHashTable *ppts1; 00183 rv = g_hash_table_lookup(matdb->materials, mat); 00184 if(rv == NULL) { 00185 fprintf(stderr, "matdb::get_material: unable to find material %s in materials database!\n", mat); 00186 *err = 1; 00187 return nan("NaN"); 00188 } else { 00189 ppts1 = ((struct matdb_material*)rv)->properties; 00190 } 00191 rv = g_hash_table_lookup(ppts1, ppt); 00192 if(rv == NULL) { 00193 fprintf(stderr, "matdb.c::get_property2: unable to find property %s in material %s\n", ppt, mat); 00194 *err = 4; 00195 return nan("NaN"); 00196 } 00197 *err = 0; 00198 return *(double*)rv; 00199 } 00200 double get_property2(const struct matdb* matdb, const char* ppt, const char* mat1, const char* mat2, double x, int* err){ 00201 if((x < 0) || (x>0) || ((x != 1.0) && (mat2 == NULL))){ 00202 fprintf(stderr, "matdb::get_material: material %s(%e)%s doesn't exist: x not in range [0, 1], or x==1 and mat2 is NULL\n", mat1, x, mat2); 00203 *err = 1; 00204 return nan("NaN"); 00205 } 00206 void* rv; 00207 rv = g_hash_table_lookup(matdb->materials, mat1); 00208 GHashTable *ppts1 = NULL; 00209 if(rv == NULL) { 00210 fprintf(stderr, "matdb::get_material: unable to find material %s in materials database!\n", mat1); 00211 *err = 2; 00212 return nan("NaN"); 00213 } else { 00214 ppts1 = ((struct matdb_material*)rv)->properties; 00215 } 00216 GHashTable *ppts2; 00217 if(mat2 == NULL) { 00218 ppts2 = NULL; 00219 } else { 00220 rv = g_hash_table_lookup(matdb->materials, mat2); 00221 if(rv == NULL) { 00222 fprintf(stderr, "matdb::get_material: unable to find material %s in materials database!\n", mat2); 00223 *err = 3; 00224 return nan("NaN"); 00225 } 00226 ppts2 = ((struct matdb_material*)rv)->properties; 00227 } 00228 rv = NULL; 00229 GHashTable *bowings; 00230 /*Look up and set bowings, if they exist.*/ 00231 if(mat2 != NULL) { 00232 GHashTable *ht = (GHashTable*)g_hash_table_lookup(matdb->bowings, mat1); 00233 if(ht != NULL) { 00234 rv = g_hash_table_lookup(ht, mat2); 00235 if(rv != NULL) { 00236 bowings = ((struct matdb_bowing*)rv)->properties; 00237 }else{ 00238 bowings = NULL; 00239 } 00240 }else{ 00241 bowings = NULL; 00242 } 00243 }else{ 00244 bowings=NULL; 00245 } 00246 rv = g_hash_table_lookup(ppts1, ppt); 00247 if(rv == NULL) { 00248 fprintf(stderr, "matdb.c::get_property2: unable to find property %s in material %s\n", ppt, mat1); 00249 *err = 4; 00250 return nan("NaN"); 00251 } 00252 double* val1 = (double*)rv; 00253 double* val2; 00254 double* bow; 00255 double result; 00256 if(ppts2 != NULL) { 00257 val2 = (double*)g_hash_table_lookup(ppts2, ppt); 00258 if(val2 == NULL) { 00259 fprintf(stderr, "matdb.c::clone_each_property: WARNING material %s in material %s is not set in %s; skipping for their alloy.\n", ppt, mat1, mat2); 00260 *err = 5; 00261 return nan("NaN"); 00262 }else{ 00263 if((bow = (double*)g_hash_table_lookup(bowings, ppt)) == NULL) { 00264 result = interpolate_without_bowing(*val1, *val2, x); 00265 }else{ 00266 result = interpolate_with_bowing(*val1, *val2, *bow, x); 00267 } 00268 } 00269 } else { 00270 val2=NULL; 00271 result = *val1; 00272 } 00273 /*Everything is someone else's pointers, so we don't have to free anything.*/ 00274 *err = 0; 00275 return result; 00276 } 00277 double get_bowing(const struct matdb* matdb, const char* ppt, const char* mat1, const char* mat2, int* err) { 00278 void *rv; 00279 GHashTable *bowings; 00280 /*Look up and set bowings, if they exist.*/ 00281 GHashTable *ht = (GHashTable*)g_hash_table_lookup(matdb->bowings, mat1); 00282 if(ht != NULL) { 00283 rv = g_hash_table_lookup(ht, mat2); 00284 if(rv != NULL) { 00285 bowings = ((struct matdb_bowing*)rv)->properties; 00286 }else{ 00287 *err = 1; 00288 return nan("NaN"); 00289 } 00290 }else{ 00291 *err = 2; 00292 return nan("NaN"); 00293 } 00294 double* bow; 00295 if((bow = (double*)g_hash_table_lookup(bowings, ppt)) == NULL) { 00296 *err = 3; 00297 return nan("NaN"); 00298 } 00299 *err = 0; 00300 return *bow; 00301 } 00302 00303 00304 /*TODO: parse the string out*/ 00305 double get_property(const struct matdb* matdb, const char* ppt, const char* matstring, int* err) { 00306 return get_property1(matdb, ppt, matstring, err); 00307 } 00308 00309 00310 void insert_external_material(struct matdb* matdb, const char* matname) { 00311 struct matdb_material* mat = (struct matdb_material*)malloc(sizeof(struct matdb_material)); 00312 /*Create an empty hash table for the fake material.*/ 00313 mat->name = g_string_new(matname); 00314 GString* s = g_string_new(matname); 00315 mat->properties = g_hash_table_new_full(g_str_hash, g_str_equal, free, free); 00316 g_hash_table_insert(matdb->materials, s->str, mat); 00317 g_string_free(s, FALSE); 00318 }