經過前面兩篇文章, 咱們已經解決了在手寫筆跡中的平滑問題. 本篇將講解如何讓手寫筆跡可以有筆鋒效果.php
想要讓筆跡可以有筆鋒的效果, 那麼整個筆跡確定不多是等寬的.也就是說, 要讓咱們繪製出來的筆跡線條必需要有必定的粗細變化.html
全部人都可以很天然的想到 粗細變化的原理: 運動快的地方確定線條應該更細, 運動慢的的地方細條應該更粗.是的, 這是最基本的原理, 這個想法徹底正確.node
說點題外話, 最近在看機器學習, 神經網絡模型裏面有一個叫:激活函數的東西, 它的做用就是爲了讓神經網絡具備分層的非線性映射學習的能力,
若是徹底是線性的, 在處理某些複雜狀況時,獲得的結果會很糟糕.c++
一樣, 咱們在處理手寫筆跡的時候, 線條的粗細也不該該徹底和速度是一種線性的變化關係,.git
事實上, 若是徹底按照一種線性的變化關係, 繪製出來的線條會看起來很是奇怪(親測徹底如此).程序員
因此, 在計算線條粗細的時候, 在遵循"速度越快的地方,線條更細; 速度慢的地方,線條更粗" 這一條基本準則的前提下,
也應該根據一些具體狀況, 讓線條的粗細變化具備"非線性"的能力.github
下面我基於手寫的實際狀況,提出一些問題, 你們能夠稍微思考一下:算法
1) 假設咱們的計算線條筆寬的函數就是: W_current = k * s, 其中s爲當前線段筆跡點移動的速度, k爲將速度映射爲筆寬的一個固定係數.
用戶移動時, 獲得了3個相鄰的點依次分別爲:a,b,c, 在ab線段, 移動速度接近無限大, 而在bc段移動的速度無限接近0,
事實上, 在手寫筆跡的時候,徹底有可能 前一段移動速度很是快, 到下一段距離的時候, 移動速度就馬上變得很是慢了.
我只是把可能遇到的狀況進行了誇張, 那麼, 在這種狀況下,咱們應該如何處理線條的粗細呢?vim
2) 一樣假設3個點, 兩條線段ab, bc, cd, 而且假設ab, bc有足夠的長度, 使得咱們計算出來的寬度變化看起來也是比較合理的, 這樣說可能不太容易理解.
舉個栗子: ab, bc的線段長度都爲100個像素, 計算出ab線段線條的寬度應該是5, bc線段的線條寬度該是10,
從真實手寫的狀況來看, 200個像素長度的筆跡, 只有5個像素的寬度變化,這是徹底合理的.
那麼,若是咱們用寬度5來繪製線段ab, 而後用寬度10來繪製線段bc, 咱們繪製出來的筆跡是什麼樣子的? (發揮一下想象力)微信
3) 在真實手寫的狀況下, 文字的筆跡的筆鋒主要體如今文字的哪些部位?
下面咱們分別討論這3個問題.
問題一:
若是徹底按照線性函數W_current = k * s 來計算寬度, 相鄰兩端線條的筆寬變化有可能很是大, 大到超出了咱們能夠的接受範圍.
因此咱們考慮經過某種方式來限制這種忽然的變化, 讓線條寬度的變化看起來更天然.
下面是我修正之後的計算線條寬度的函數:
W_current =
W_previous + min( abs(k*s - W_previous), distance * K_width_unit_change) (k * s-W_previous) >= 0
W_previous - min( abs(k*s - W_previous), distance * K_width_unit_change) (k * s-W_previous) < 0
W_current 當前線段的寬度
W_previous 與當前線條相鄰的前一條線段的寬度
distance 當前線條的長度
w_k 設定的一個固定閾值,表示:單位距離內, 筆跡的線條寬度能夠變化的最大量.
distance * w_k 即爲當前線段的長度內, 筆寬能夠相對於前一條線段筆寬的基礎上, 最多可以變寬或者能夠變窄多少.
這個函數多引入了2個變量(前一條線段的寬度, 還有當前的線段的距離), 在計算線條寬度時, 考慮了更多的可能性.
還增長了一種非線性的變化機制, min.這個min就是咱們的"激活函數".讓咱們的線寬再也不只具備線性的變化了.
如今, 這個計算線寬的函數,看起來已經比較完美了.
問題二:
咱們直接看一個我故意作得比較很差的示範圖:
雖然這個效果大體看起來看還行, 做爲一名追求完美的程序員, 始終以爲什麼地方不對勁.
那麼咱們再把這個問題放大到一種極端的狀況:
這樣問題就很明顯了.
我解決這個問題的方式是:利用微分的思想, 把線段再次細分紅多條子線段, 寬度的變化均勻的分佈在這些細分的子線段上.
這樣, 咱們的線條寬度變化看起來就更加天然了.
問題三:
在平時的書寫過程當中, 筆鋒主要體如今筆畫的起始位置, 轉角位置, 和筆畫結束的位置.
在筆跡轉角的位置體現出筆鋒看起來比較困難, 可是在筆跡開始和結束的地方作一些文章仍是比較容易.
個人具體作法是這樣, 在筆跡開始的前5個點(這個'5', 是我隨便想出來的, 也可4,6,7,8), 讓筆跡的寬細變化更加明顯
在筆跡的結束位置, 無論以前的線段寬度是多少, 都讓其在最後位置收縮爲最小筆寬.
更好的理由我也說不出來爲何,應該是屬於程序員的第七感吧, 感受這樣作會比較好. 並且事實證實效果的確不錯.
其實這裏也體現了"非線性"變化的思想, 由於我以爲這一點比較重要, 因此單獨提出來.
解決以上3個問題, 離這個算法的成功, 就還差一些細節的問題了.(雖然是細節問題, 可是如下這幾個須要注意的細節很是很是很是重要, 說三遍!!!!!!!)
下面我就不買關子, 直接告訴你們須要注意的地方:
1) 在實際的狀況中, 移動 定位設備(鼠標,手寫筆,或者觸摸屏)時, 設備發送給咱們的mouse_move消息會很是的多, 須要設立一個
時間閾值, 好比前一次消息到這一次消息的間隔時間小於30毫秒, 就把這個點廢棄掉. 不然, 點太多, 每一個都處理, 基本上都是多餘的計算..
2) 在實際狀況中, 須要設立一個距離閾值, 當本次獲得的點, 到上一個點的距離小於這個閾值時, 把這個點捨棄掉, 距離太近, 也是多餘的計算.
以上內容, 差很少就是手寫筆跡算法中全部技術難點和須要注意的細節了.
下面把C++實現的源代碼分享給你們, 其中z_math.h, z_math.c使用純c實現,除了c標準庫,沒有其它任何依賴,能夠毫無壓力的移植到各個支持c/c++語言的任何平臺.
z_math是算法的核心實現部分:
1 /* 2 ===================================================================================== 3 * Filename: z_math.h 4 * Description: 5 * Version: 2.0 6 * Created: 06/23/2016 14:53:43 7 * Revision: none 8 * Compiler: gcc 9 * Author: zl(88911562@qq.com), 10 * Organization: 11 * ===================================================================================== 12 */ 13 //_________________________________ 14 // stl on mac location is: 15 // /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1 16 // Mac OS X 10.9+ no longer uses GCC/libstdc++ but uses libc++ and Clang. 17 //--------------------------------- 18 //td c++ (STL, streams, ...) : Modified libstdc++ headers for use with ctags 19 //use ctags for c++(stl,streams....) 20 //www.vim.org/scripts/script.php?script_id=2358 21 //ctags -R --c++-kinds=+p --fields=+ias --extra=+q --language-force=c++ cpp_src 22 //sudo ctags -R --c++-kinds=+p --fields=+ias --extra=+q --language-force=c++ ./ 23 //================================= */ 24 #ifndef z_math_h_ 25 #define z_math_h_ 26 27 #ifdef __cplusplus 28 extern "C" { 29 #endif 30 31 #include <stdint.h> 32 33 typedef struct z_point_s z_point; 34 typedef struct z_fpoint_s z_fpoint; 35 typedef struct z_ipoint_s z_ipoint; 36 typedef struct z_fpoint_array_s z_fpoint_array; 37 typedef struct z_fpoint_arraylist_node_s z_fpoint_arraylist_node; 38 typedef struct z_fpoint_arraylist_s z_fpoint_arraylist; 39 40 struct z_point_s { 41 float x, y; 42 }; 43 44 struct z_fpoint_s{ 45 z_point p; 46 float w; 47 }; 48 49 struct z_ipoint_s { 50 z_point p; 51 int64_t t; 52 }; 53 54 struct z_fpoint_array_s { 55 z_fpoint *point; 56 float maxwidth; 57 float minwidth; 58 int ref; 59 int len; 60 int cap; 61 62 z_point last_point; 63 float last_width; 64 int64_t last_ms; 65 }; 66 67 struct z_fpoint_arraylist_node_s { 68 z_fpoint_array *a; 69 z_fpoint_arraylist_node *n; 70 }; 71 72 struct z_fpoint_arraylist_s { 73 int ref; 74 z_fpoint_arraylist_node *first; 75 z_fpoint_arraylist_node *end; 76 z_fpoint_arraylist_node *cur; 77 }; 78 79 z_fpoint_array *z_keep_fpoint_array(z_fpoint_array *a); 80 void z_drop_fpoint_array(z_fpoint_array *a); 81 82 z_fpoint_arraylist* z_keep_fpoint_arraylist(z_fpoint_arraylist *l); 83 void z_drop_fpoint_arraylist(z_fpoint_arraylist *l); 84 85 z_fpoint_array *z_new_fpoint_array(int initsize, float maxwidth, float minwidth); 86 z_fpoint_array *z_resize_fpoints_array(z_fpoint_array* a, int size); 87 88 z_fpoint_arraylist *z_new_fpoint_arraylist(); 89 void z_fpoint_arraylist_append(z_fpoint_arraylist *l, z_fpoint_array *a); 90 // must be drop after used 91 z_fpoint_array *z_fpoint_arraylist_append_new(z_fpoint_arraylist *l, float maxwidth, float minwidth); 92 void z_fpoint_arraylist_removelast(z_fpoint_arraylist *l); 93 94 float z_movespeed(z_ipoint s, z_ipoint e); 95 float z_distance(z_point s, z_point e); 96 void z_fpoint_add_xyw(z_fpoint_array *a, float x, float y, float w); 97 void z_fpoint_add(z_fpoint_array *a, z_fpoint p); 98 void z_fpoint_differential_add(z_fpoint_array *a, z_fpoint p); 99 void z_square_bezier(z_fpoint_array *a, z_fpoint b, z_point c, z_fpoint e); 100 float z_linewidth(z_ipoint b, z_ipoint e, float w, float step); 101 102 float z_insert_point(z_fpoint_array *arr, z_point point); 103 void z_insert_last_point(z_fpoint_array *arr, z_point e); 104 105 106 typedef struct z_list_node_s z_list_node; 107 struct z_list_node_s { 108 void *data; 109 z_list_node *n; 110 z_list_node *p; 111 }; 112 typedef void*(*z_list_node_alloc_fun)(); 113 typedef void(*z_list_node_drop_fun) (void *data); 114 115 116 struct z_list_s { 117 z_list_node_alloc_fun alloc; 118 z_list_node_drop_fun drop; 119 z_list_node *first; 120 z_list_node *last; 121 }; 122 typedef struct z_list_s z_list; 123 124 z_list *z_list_new(z_list_node_alloc_fun allocfun, z_list_node_drop_fun dropfun); 125 void *z_list_append_new(z_list *zlist); 126 void *z_list_remove_last(z_list *zlist); 127 void z_list_clear(z_list *zlist); 128 void z_list_free(z_list *zlist); 129 130 /* digest must be 33 char size */ 131 // void z_text_md5(const char* str, char *digest); 132 133 #ifdef __cplusplus 134 } 135 #endif 136 137 #endif
1 /* 2 ===================================================================================== 3 * Filename: z_math.c 4 * Description: 5 * Version: 1.0 6 * Created: 06/23/2016 14:53:43 7 * Revision: none 8 * Compiler: gcc 9 * Author: zl(88911562@qq.com), 10 * Organization: 11 * ===================================================================================== 12 */ 13 #include <math.h> 14 #include <stdio.h> 15 #include <string.h> 16 #include <stdlib.h> 17 #include <time.h> 18 #include "z_math.h" 19 20 #define z_malloc_struct(t) (t*)calloc(1, sizeof(t)) 21 static void* z_malloc_array(unsigned int count, unsigned int size); 22 static void* z_resize_array(void *p, size_t count, size_t size); 23 24 static void z_fpoint_array_set_last_info(z_fpoint_array *arr, z_point last_point, float last_width); 25 26 /***************************** mac stdlib location: 27 Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/stdio.h 28 */ 29 static float z_square(float f){ return (float)f*f; }; 30 static float z_cubic_(float f){ return (float)powf(f, 3); }; 31 32 typedef struct z_bezier_factors_s { 33 float bezier_step; // must be divisible by 1.0f 34 float max_width_diff; // max width diff between two near lines 35 float max_move_speed; // 36 float max_linewith; 37 } z_bezier_factors ; 38 39 int z_point_equals(z_point *p1, z_point *p2) { 40 return (p1->x==p2->x&&p1->y==p2->y) ? 1 : 0; 41 } 42 43 z_fpoint_array *z_keep_fpoint_array(z_fpoint_array *a) { 44 if(a) a->ref++; 45 return a; 46 } 47 48 void z_drop_fpoint_array(z_fpoint_array *a) { 49 if(!a) return; 50 51 if( !(--(a->ref)) ) { 52 free(a); 53 } 54 } 55 56 z_fpoint_arraylist *z_keep_fpoint_arraylist(z_fpoint_arraylist *l) { 57 if(!l) return NULL; 58 l->ref++; 59 return l; 60 } 61 62 void z_drop_fpoint_arraylist(z_fpoint_arraylist *l) { 63 if(!l) return; 64 65 if( !(--(l->ref)) ) { 66 z_fpoint_arraylist_node *c = l->first; 67 z_fpoint_arraylist_node *n; 68 while(c) { 69 z_drop_fpoint_array(c->a); 70 n = c->n; 71 free(c); 72 c = n; 73 } 74 } 75 } 76 77 static const float defualt_max_width = 5.0f; 78 static const float default_min_width = 1.0f; 79 80 z_fpoint_array *z_new_fpoint_array(int initsize, float maxwidth, float minwidth) { 81 if(initsize<=0) return NULL; 82 z_fpoint_array *a = malloc(sizeof(z_fpoint_array)); 83 a->point = z_malloc_array(initsize, sizeof(z_fpoint)); 84 a->ref = 1; 85 a->len = 0; 86 87 if(maxwidth<0 || minwidth<0 || maxwidth<minwidth ){ 88 maxwidth = defualt_max_width; 89 minwidth = default_min_width; 90 } 91 92 a->maxwidth = maxwidth; 93 a->minwidth = minwidth; 94 95 a->cap = initsize; 96 return a; 97 } 98 99 z_fpoint_array *z_resize_fpoints_array(z_fpoint_array* a, int count){ 100 if(!a || count<=0) return NULL; 101 102 a->point = (z_fpoint*)z_resize_array(a->point, count, sizeof(z_fpoint)); 103 a->cap = count; 104 a->len = min(a->cap, a->len); 105 return a; 106 } 107 108 z_fpoint_arraylist *z_new_fpoint_arraylist() { 109 z_fpoint_arraylist *l = z_malloc_struct(z_fpoint_arraylist); 110 l->ref = 1; 111 l->first = l->end = NULL; 112 return l; 113 } 114 115 void z_fpoint_arraylist_append(z_fpoint_arraylist *l, z_fpoint_array *a) { 116 z_fpoint_arraylist_node *node = z_malloc_struct(z_fpoint_arraylist_node); 117 node->a = z_keep_fpoint_array(a); 118 node->n = NULL; 119 120 if(!l->first) { 121 l->first = node; 122 } 123 else { 124 l->end->n = node; 125 } 126 127 l->end = node; 128 } 129 130 z_fpoint_array *z_fpoint_arraylist_append_new(z_fpoint_arraylist *l, float max, float min) { 131 z_fpoint_array *a = z_new_fpoint_array(24, max, min); 132 z_fpoint_arraylist_append(l, a); 133 printf("append new points array\n"); 134 return a; 135 } 136 137 void z_fpoint_arraylist_removelast(z_fpoint_arraylist *l) { 138 139 z_fpoint_arraylist_node *c = l->first; 140 141 z_drop_fpoint_array(l->end->a); 142 free(l->end); 143 144 while(c->n != l->end) { c = c->n; } 145 146 c->n = NULL; 147 l->end = c; 148 } 149 150 z_fpoint_array *z_auto_increase_fpoints_array(z_fpoint_array *a) { 151 int cap = a->cap + (a->cap+3)/4; 152 return z_resize_fpoints_array(a, cap); 153 } 154 155 float z_movespeed(z_ipoint s, z_ipoint e) { 156 float d = z_distance(s.p, e.p); 157 return (0==d) ? 0 : d/(e.t-s.t); 158 } 159 160 float z_distance(z_point b, z_point e){ 161 return (float)sqrtf( z_square(e.x-b.x) + z_square(e.y-b.y) ); 162 } 163 164 void z_fpoint_add_xyw(z_fpoint_array *a, float x, float y, float w) { 165 if( !a || (a->point[a->len-1].p.x==x && a->point[a->len-1].p.y==y) ) return; 166 167 if(a->len==a->cap) 168 z_auto_increase_fpoints_array(a); 169 170 z_fpoint *p = a->point + (a->len++); 171 p->p.x = x; p->p.y = y; p->w = w; 172 } 173 174 void z_fpoint_add(z_fpoint_array *a, z_fpoint p) { 175 z_fpoint_add_xyw(a, p.p.x, p.p.y, p.w); 176 } 177 178 void z_fpoint_differential_add(z_fpoint_array *a, z_fpoint p) { 179 if(!a) return; 180 181 if( a->len==0 ) { 182 z_fpoint_add(a, p); 183 return; 184 } 185 186 // #define bad_show 187 #ifdef bad_show 188 z_fpoint_add(a, p); 189 return; 190 #endif 191 float max_diff = 0.1f; 192 z_fpoint *last = a->point + (a->len-1); 193 z_point sp = last->p; 194 float sw = last->w; 195 196 int n = (int)((fabsf(p.w - last->w) / max_diff) + 1); 197 float x_step = (p.p.x - sp.x) / n; 198 float y_step = (p.p.y - sp.y) / n; 199 float w_step = (p.w - sw) / n; 200 201 int i; 202 for(i=0; i<(n-1); i++ ){ 203 sp.x += x_step; 204 sp.y += y_step; 205 sw += w_step; 206 z_fpoint_add_xyw(a, sp.x, sp.y, sw); 207 } 208 z_fpoint_add(a, p); 209 } 210 211 void z_square_bezier(z_fpoint_array *a, z_fpoint b, z_point c, z_fpoint e){ 212 if(!a) return; 213 const float f = 0.1f; 214 for(float t=f; t<=1.0; t+=f ) { 215 float x1 = z_square(1-t)*b.p.x + 2*t*(1-t)*c.x + z_square(t)*e.p.x; 216 float y1 = z_square(1-t)*b.p.y + 2*t*(1-t)*c.y + z_square(t)*e.p.y; 217 float w = b.w + (t* (e.w-b.w)); 218 z_fpoint pw = { {x1, y1}, w}; 219 z_fpoint_differential_add(a, pw); 220 } 221 } 222 223 float z_linewidth(z_ipoint b, z_ipoint e, float bwidth, float step) { 224 const float max_speed = 2.0f; 225 float d = z_distance(b.p, e.p); 226 float s = d / (e.t - b.t); s = s > max_speed ? max_speed : s; 227 float w = (max_speed-s) / max_speed; 228 float max_dif = d * step; 229 if( w<0.05f ) w = 0.05f; 230 if( fabs( w-bwidth ) > max_dif ) { 231 if( w > bwidth ) 232 w = bwidth + max_dif; 233 else 234 w = bwidth - max_dif; 235 } 236 // printf("d:%.4f, time_diff:%lld, speed:%.4f, width:%.4f\n", d, e.t-b.t, s, w); 237 return w; 238 } 239 240 241 float z_insert_point(z_fpoint_array *arr, z_point point) { 242 243 if(!arr) return 0; 244 int len = arr->len; 245 246 z_point zp = {point.x, point.y}; 247 if( 0==len ){ 248 z_fpoint p = {zp, 0.4f}; 249 z_fpoint_add(arr, p); 250 z_fpoint_array_set_last_info(arr, point, p.w); 251 return p.w; 252 } 253 254 int64_t cur_ms = clock(); 255 float last_width = arr->last_width; 256 int64_t last_ms = arr->last_ms; 257 z_point last_point = arr->last_point; 258 259 printf("cur_ms - last_ms = 0x%llx\n", cur_ms - last_ms); 260 // 兩次採樣時間小於25毫秒, 或者距離小於2個像素, 不採樣計算!!! 261 float distance = z_distance(point, last_point); 262 if( (cur_ms-last_ms) < 50 || distance < 3) { 263 return 0; 264 } 265 266 float step = arr->len > 4 ? 0.05f : 0.2f; 267 z_ipoint bt = { {last_point.x,last_point.y}, last_ms}; 268 z_ipoint et = { zp, cur_ms}; 269 float w = (z_linewidth(bt, et, last_width, step) + last_width) / 2; 270 z_fpoint_array *points = z_new_fpoint_array(51, arr->maxwidth, arr->minwidth); 271 z_fpoint tmppoint = arr->point[len-1]; 272 z_fpoint_add(points, tmppoint); 273 274 if( 1==len ) { 275 z_fpoint p = { {(bt.p.x + et.p.x + 1) / 2, (bt.p.y + et.p.y +1) / 2}, w}; 276 z_fpoint_differential_add(points, p); 277 w = p.w; 278 } 279 else { 280 z_fpoint bw = tmppoint; 281 z_point c = {last_point.x,last_point.y}; 282 z_fpoint ew = {{(last_point.x + point.x)/2, (last_point.y + point.y)/2}, w}; 283 z_square_bezier(points, bw, c, ew); 284 } 285 286 // escape the first point 287 int i; 288 for(i=1; i<points->len; i++) { 289 z_fpoint_add(arr, points->point[i]); 290 } 291 292 z_drop_fpoint_array(points); 293 z_fpoint_array_set_last_info(arr, point, w); 294 295 return w; 296 } 297 298 void z_insert_last_point(z_fpoint_array *arr, z_point e) { 299 if(!arr) return; 300 long len= arr->len; 301 if(len==0 ) return; 302 z_fpoint_array *points = z_new_fpoint_array(51, arr->maxwidth, arr->minwidth); 303 z_fpoint zb = arr->point[len-1]; 304 z_fpoint_add(points, zb); 305 306 z_fpoint ze = { {e.x, e.y}, 0.1f}; 307 z_fpoint_differential_add(points, ze); 308 int i; 309 for(i=1; i<points->len; i++) { 310 z_fpoint_add(arr, points->point[i]); 311 } 312 z_drop_fpoint_array(points); 313 } 314 315 z_list *z_list_new(z_list_node_alloc_fun allocfun, z_list_node_drop_fun dropfun) 316 { 317 z_list *l = NULL; 318 l = z_malloc_struct(z_list); 319 l->alloc = allocfun; 320 l->drop = dropfun; 321 l->first = l->last = NULL; 322 return l; 323 } 324 325 void *z_list_append_new(z_list *zlist) 326 { 327 z_list_node *node = NULL; 328 void *data = NULL; 329 330 if(!zlist->alloc || !zlist->drop) 331 return NULL; 332 333 node = z_malloc_struct(z_list_node); 334 node->data = zlist->alloc(); 335 node->n = NULL; 336 node->p = NULL; 337 338 if(node) { 339 if(!zlist->first) { 340 zlist->first = zlist->last = node; 341 } 342 else { 343 node->n = NULL; 344 node->p = zlist->last; 345 zlist->last->n = node; 346 zlist->last = node; 347 } 348 data = node->data; 349 } 350 351 return data; 352 } 353 void *z_list_remove_last(z_list *zlist) 354 { 355 void *data = NULL; 356 z_list_node *tmp = zlist->last; 357 if(zlist->last) { 358 tmp = zlist->last; 359 if(zlist->last==zlist->first){ 360 zlist->last = zlist->first = NULL; 361 } 362 else { 363 zlist->last = tmp->p; 364 zlist->last->n = NULL; 365 } 366 } 367 368 if(tmp) { 369 data = tmp->data; 370 free(tmp); 371 } 372 373 return data; 374 } 375 376 void z_list_clear(z_list *zlist) 377 { 378 while (zlist->first) 379 zlist->drop(z_list_remove_last(zlist)); 380 } 381 382 void z_list_free(z_list *zlist) 383 { 384 z_list_clear(zlist); 385 free(zlist); 386 } 387 388 /* digest must be 33 char size */ 389 // void 390 // z_text_md5(const char* str, char *digest) 391 // { 392 // int len = strlen(str); 393 // unsigned char d[16]; 394 // fz_md5 state; 395 // fz_md5_init(&state); 396 // fz_md5_update(&state, (const unsigned char*)str, len); 397 // fz_md5_final(&state, d); 398 // 399 // int i; 400 // for(i=0; i<(int)sizeof(d); i++) { 401 // sprintf(digest, "%02x", d[i]); 402 // digest+=2; 403 // } 404 // *digest = '\0'; 405 // } 406 407 void* z_malloc_array(unsigned int count, unsigned int size) { 408 unsigned int totalsize = count * size; 409 if (totalsize <= 0) return 0; 410 411 void *buffer = malloc(count * size); 412 if(buffer) memset(buffer, 0, count * size); 413 return buffer; 414 } 415 416 void* z_resize_array(void *p, size_t count, size_t size) { 417 void *np = 0; 418 size_t total_size = count * size; 419 420 if (total_size <= 0) 421 return np; 422 423 np = realloc(p, total_size); 424 425 return np; 426 } 427 428 void z_fpoint_array_set_last_info(z_fpoint_array *arr, z_point last_point, float last_width) { 429 if (!arr) return; 430 arr->last_point = last_point; 431 arr->last_ms = clock(); 432 arr->last_width = last_width; 433 printf("reset last ms to 0x%llx\n", arr->last_ms); 434 }
前幾天有個公司讓我優化一下個人算法, 我又優化了一下, 提供出了一個 :
快樂的時光老是過得那麼快, 留下的老是無盡的唏噓和感嘆, 又到時間和朋友們講拜拜了!!!
最後展現一張在解決這些問題時,留下的真跡:
手寫筆跡這一個系列總算是寫完了.在這幾篇原創文章中, 我有不少地方沒有辦法徹底把本身的想法表達清楚,這可能也是不少程序員攻城獅的通病, 表達能力不怎麼樣.
若是你們有什麼不清楚或者我說得有問題的地方, 能夠在留言區留言.我會盡可能回答.
下面!!!!!!!!我不得再也不次提起一件很讓我氣憤的事情!!!!!!!
無良公司老闆拖欠兩個月工資了, 窮得叮噹響,我靠!!!!!!!!如今天天吃8塊錢的蛋炒飯, 早上點一份,中午吃一半, 晚上吃一半, 日子真實苦啊..
你們若是你們以爲這篇文章對您有幫助, 又願意打賞一些銀兩, 請拿起你的手機, 打開你的微信, 掃一掃下方二維碼, 做爲一個有骨氣的程序員攻城獅, 我很是願意接受你們的支助...哈哈哈!!!