Switch to unified view

a b/3D Reconstruction/3D Visualization/obj_display.m
1
function obj_display ( input_file_name )
2
3
%*****************************************************************************80
4
%
5
%% OBJ_DISPLAY displays the faces of a shape defined by an OBJ file.
6
%
7
%  Usage:
8
%
9
%    obj_display ( 'file.obj' )
10
%
11
%  Licensing:
12
%
13
%    This code is distributed under the GNU LGPL license.
14
%
15
%  Modified:
16
%
17
%    27 September 2008
18
%
19
%  Author:
20
%
21
%    John Burkardt
22
%
23
  timestamp ( );
24
25
  fprintf ( 1, '\n' );
26
  fprintf ( 1, 'OBJ_DISPLAY\n' );
27
  fprintf ( 1, '  MATLAB version\n' );
28
  fprintf ( 1, '\n' );
29
  fprintf ( 1, '  Reads an object in an ASCII OBJ file.\n' );
30
  fprintf ( 1, '  Display it as a MATLAB shape.\n' );
31
%
32
%  If at least one command line argument, it's the input file name.
33
%
34
  if ( nargin < 1 )
35
36
    fprintf ( 1, '\n' );
37
    fprintf ( 1, 'OBJ_DISPLAY:\n' );
38
    input_file_name = input ( 'Enter the name of the input file:' );
39
40
  end
41
%
42
%  Get sizes.
43
%
44
  [ node_num, face_num, normal_num, order_max ] = obj_size ( input_file_name );
45
%
46
%  Print the sizes.
47
%
48
  obj_size_print ( input_file_name, node_num, face_num, normal_num, order_max );
49
%
50
%  Get the data.
51
%
52
  [ node_xyz, face_order, face_node ] = ...
53
    obj_read ( input_file_name, node_num, face_num, normal_num, order_max );
54
%
55
%  FACE_NODE may contain polygons of different orders.
56
%  To make the call to PATCH, we will assume all the polygons are the same order.
57
%  To do so, we'll simply "stutter" the first node in each face list.
58
%
59
  for face = 1 : face_num
60
    face_node(face_order(face)+1:order_max,face) = face_node(1,face);
61
  end
62
%
63
%  If any node index is still less than 1, set the whole face to 1's.
64
%  We're giving up on this presumably meaningless face, but we need to
65
%  do it in a way that keeps MATLAB happy!
66
%
67
  for face = 1 : face_num
68
    for i = 1 : order_max
69
      face_node(i,face) = max ( face_node(i,face), 1 );
70
    end
71
  end
72
%
73
%  Display the shape.
74
%
75
  handle = patch ( 'Vertices', node_xyz', 'Faces', face_node' );
76
  
77
  set ( handle, 'FaceColor', [0.5, 0.6, 0.8], 'EdgeColor', 'Black' );
78
79
  axis equal; 
80
  grid on;
81
82
  xlabel ( '--X axis--' )
83
  ylabel ( '--Y axis--' )
84
  zlabel ( '--Z axis--' )
85
%
86
%  The TITLE function will interpret underscores in the title.
87
%  We need to unescape such escape sequences!
88
%
89
  title_string = s_escape_tex ( input_file_name );
90
  title ( title_string )
91
%
92
%  Terminate.
93
%
94
  fprintf ( 1, '\n' );
95
  fprintf ( 1, 'OBJ_DISPLAY:\n' );
96
  fprintf ( 1, '  Normal end of execution.\n' );
97
98
  fprintf ( 1, '\n' );
99
  timestamp ( );
100
101
  return
102
end
103
function c = ch_cap ( c )
104
105
%*****************************************************************************80
106
%
107
%% CH_CAP capitalizes a single character.
108
%
109
%  Licensing:
110
%
111
%    This code is distributed under the GNU LGPL license.
112
%
113
%  Modified:
114
%
115
%    22 November 2003
116
%
117
%  Author:
118
%
119
%    John Burkardt
120
%
121
%  Parameters:
122
%
123
%    Input, character C, the character to capitalize.
124
%
125
%    Output, character C, the capitalized character.
126
%
127
  if ( 'a' <= c && c <= 'z' )
128
    c = c + 'A' - 'a';
129
  end
130
131
  return
132
end
133
function truefalse = ch_eqi ( c1, c2 )
134
135
%*****************************************************************************80
136
%
137
%% CH_EQI is a case insensitive comparison of two characters for equality.
138
%
139
%  Example:
140
%
141
%    CH_EQI ( 'A', 'a' ) is TRUE.
142
%
143
%  Licensing:
144
%
145
%    This code is distributed under the GNU LGPL license.
146
%
147
%  Modified:
148
%
149
%    28 July 2000
150
%
151
%  Author:
152
%
153
%    John Burkardt
154
%
155
%  Parameters:
156
%
157
%    Input, character C1, C2, the characters to compare.
158
%
159
%    Output, logical TRUEFALSE, is TRUE (1) if the characters are equal.
160
%
161
  FALSE = 0;
162
  TRUE = 1;
163
164
  if ( ch_cap ( c1 ) == ch_cap ( c2 ) )
165
    truefalse = TRUE;
166
  else
167
    truefalse = FALSE;
168
  end
169
170
  return
171
end
172
function value = ch_index ( s, c )
173
174
%*****************************************************************************80
175
%
176
%% CH_INDEX is the first occurrence of a character in a string.
177
%
178
%  Licensing:
179
%
180
%    This code is distributed under the GNU LGPL license.
181
%
182
%  Modified:
183
%
184
%    01 May 2004
185
%
186
%  Author:
187
%
188
%    John Burkardt
189
%
190
%  Parameters:
191
%
192
%    Input, string S, the string to be searched.
193
%
194
%    Input, character C, the character to be searched for.
195
%
196
%    Output, integer VALUE, the location of the first occurrence of C 
197
%    in the string, or 0 if C does not occur.
198
%
199
  value = 0;
200
201
  for i = 1 : length ( s )
202
203
    if ( s(i:i) == c )
204
      value = i;
205
      return
206
    end
207
208
  end
209
210
  return
211
end
212
function value = ch_is_control ( ch )
213
214
%*****************************************************************************80
215
%
216
%% CH_IS_CONTROL is TRUE if a character is a control character.
217
%
218
%  Discussion:
219
%
220
%    A "control character" has ASCII code <= 31 or 127 <= ASCII code.
221
%
222
%  Licensing:
223
%
224
%    This code is distributed under the GNU LGPL license.
225
%
226
%  Modified:
227
%
228
%    27 September 2008
229
%
230
%  Author:
231
%
232
%    John Burkardt
233
%
234
%  Parameters:
235
%
236
%    Input, character CH, the character to be tested.
237
%
238
%    Output, integer CH_IS_CONTROL, TRUE if the character is a control
239
%    character, and FALSE otherwise.
240
%
241
  if ( ch <= 31 || 127 <= ch )
242
    value = 1;
243
  else
244
    value = 0;
245
  end
246
247
  return
248
end
249
function truefalse = ch_is_digit ( c )
250
251
%*****************************************************************************80
252
%
253
% CH_IS_DIGIT returns TRUE if the character C is a digit.
254
%
255
%  Licensing:
256
%
257
%    This code is distributed under the GNU LGPL license.
258
%
259
%  Modified:
260
%
261
%    11 December 2003
262
%
263
%  Author:
264
%
265
%    John Burkardt
266
%
267
%  Parameters:
268
%
269
%    Input, character C, a character.
270
%
271
%    Output, integer TRUEFALSE, is TRUE (1) if C is a digit, FALSE (0) otherwise.
272
%
273
  TRUE = 1;
274
  FALSE = 0;
275
276
  if ( '0' <= c && c <= '9' )
277
    truefalse = TRUE;
278
  else
279
    truefalse = FALSE;
280
  end
281
282
  return
283
end
284
function digit = ch_to_digit ( c )
285
286
%*****************************************************************************80
287
%
288
%% CH_TO_DIGIT returns the integer value of a base 10 digit.
289
%
290
%  Example:
291
%
292
%     C   DIGIT
293
%    ---  -----
294
%    '0'    0
295
%    '1'    1
296
%    ...  ...
297
%    '9'    9
298
%    ' '    0
299
%    'X'   -1
300
%
301
%  Licensing:
302
%
303
%    This code is distributed under the GNU LGPL license.
304
%
305
%  Modified:
306
%
307
%    22 November 2003
308
%
309
%  Author:
310
%
311
%    John Burkardt
312
%
313
%  Parameters:
314
%
315
%    Input, character C, the decimal digit, '0' through '9' or blank
316
%    are legal.
317
%
318
%    Output, integer DIGIT, the corresponding integer value.  If C was
319
%    'illegal', then DIGIT is -1.
320
%
321
  if ( '0' <= c && c <= '9' )
322
323
    digit = c - '0';
324
325
  elseif ( c == ' ' )
326
327
    digit = 0;
328
329
  else
330
331
    digit = -1;
332
333
  end
334
335
  return
336
end
337
function [ node_xyz, face_order, face_node, normal_vector, vertex_normal ] = ...
338
  obj_read ( input_file_name, node_num, face_num, normal_num, order_max )
339
340
%*****************************************************************************80
341
%
342
%% OBJ_READ reads graphics information from a Wavefront OBJ file.
343
%
344
%  Discussion:
345
%
346
%    It is intended that the information read from the file can
347
%    either start a whole new graphics object, or simply be added
348
%    to a current graphics object via the '<<' command.
349
%
350
%    This is controlled by whether the input values have been zeroed
351
%    out or not.  This routine simply tacks on the information it
352
%    finds to the current graphics object.
353
%
354
%  Example:
355
%
356
%    #  magnolia.obj
357
%
358
%    v -3.269770 -39.572201 0.876128
359
%    v -3.263720 -39.507999 2.160890
360
%    ...
361
%    v 0.000000 -9.988540 0.000000
362
%    vn 1.0 0.0 0.0
363
%    ...
364
%    vn 0.0 1.0 0.0
365
%
366
%    f 8 9 11 10
367
%    f 12 13 15 14
368
%    ...
369
%    f 788 806 774
370
%
371
%  Licensing:
372
%
373
%    This code is distributed under the GNU LGPL license.
374
%
375
%  Modified:
376
%
377
%    27 September 2008
378
%
379
%  Author:
380
%
381
%    John Burkardt
382
%
383
%  Parameters:
384
%
385
%    Input, string INPUT_FILE_NAME, the name of the input file.
386
%
387
%    Input, integer NODE_NUM, the number of points.
388
%
389
%    Input, integer FACE_NUM, the number of faces.
390
%
391
%    Input, integer NORMAL_NUM, the number of normal vectors.
392
%
393
%    Input, integer ORDER_MAX, the maximum number of vertices per face.
394
%
395
%    Output, real NODE_XYZ(3,NODE_NUM), the coordinates of points.
396
%
397
%    Output, integer FACE_ORDER(FACE_NUM), the number of vertices per face.
398
%
399
%    Output, integer FACE_NODE(ORDER_MAX,FACE_NUM), the nodes making faces.
400
%
401
%    Output, real NORMAL_VECTOR(3,NORMAL_NUM), normal vectors.
402
%
403
%    Output, integer VERTEX_NORMAL(ORDER_MAX,FACE_NUM), the indices of normal
404
%    vectors per vertex.
405
%
406
  face = 0;
407
  node = 0;
408
  normal = 0;
409
  text_num = 0;
410
411
  face_node = zeros ( order_max, face_num );
412
  face_order = zeros ( face_num, 1 );
413
  node_xyz = zeros ( 3, node_num );
414
  normal_vector = zeros ( 3, normal_num );
415
  vertex_normal = zeros ( order_max, face_num );
416
%
417
%  If no file input, try to get one from the user.
418
%
419
  if ( nargin < 1 )
420
    input_file_name = input ( 'Enter the name of the ASCII OBJ file.' );
421
    if ( isempty ( input_file_name ) )
422
      return
423
    end
424
  end
425
%
426
%  Open the file.
427
%
428
  input_file_unit = fopen ( input_file_name, 'r' );
429
430
  if ( input_file_unit < 0 )
431
    fprintf ( 1, '\n' );
432
    fprintf ( 1, 'OBJ_READ - Fatal error!\n' );
433
    fprintf ( 1, '  Could not open the file "%s".\n', input_file_name );
434
    error ( 'OBJ_READ - Fatal error!' );
435
  end
436
%
437
%  Read a line of text from the file.
438
%
439
  while ( 1 )
440
441
    text = fgetl ( input_file_unit );
442
443
    if ( text == -1 )
444
      break
445
    end
446
447
    text_num = text_num + 1;
448
%
449
%  Replace any control characters (in particular, TAB's) by blanks.
450
%
451
    s_control_blank ( text );
452
453
    done = 1;
454
    word_index = 0;
455
%
456
%  Read a word from the line.
457
%
458
    [ word, done ] = word_next_read ( text, done );
459
%
460
%  If no more words in this line, read a new line.
461
%
462
    if ( done )
463
      continue
464
    end
465
%
466
%  If this word begins with '#' or '$', then it's a comment.  Read a new line.
467
%
468
    if ( word(1) == '#' || word(1) == '$' )
469
      continue
470
    end
471
472
    word_index = word_index + 1;
473
474
    if ( word_index == 1 )
475
      word_one = word;
476
    end
477
%
478
%  BEVEL
479
%  Bevel interpolation.
480
%
481
    if ( s_eqi ( word_one, 'BEVEL' ) )
482
%
483
%  BMAT
484
%  Basis matrix.
485
%
486
    elseif ( s_eqi ( word_one, 'BMAT' ) )
487
%
488
%  C_INTERP
489
%  Color interpolation.
490
%
491
    elseif ( s_eqi ( word_one, 'C_INTERP' ) )
492
%
493
%  CON
494
%  Connectivity between free form surfaces.
495
%
496
    elseif ( s_eqi ( word_one, 'CON' ) )
497
%
498
%  CSTYPE
499
%  Curve or surface type.
500
%
501
    elseif ( s_eqi ( word_one, 'CSTYPE' ) )
502
%
503
%  CTECH
504
%  Curve approximation technique.
505
%
506
    elseif ( s_eqi ( word_one, 'CTECH' ) )
507
%
508
%  CURV
509
%  Curve.
510
%
511
    elseif ( s_eqi ( word_one, 'CURV' ) )
512
%
513
%  CURV2
514
%  2D curve.
515
%
516
    elseif ( s_eqi ( word_one, 'CURV2' ) )
517
%
518
%  D_INTERP
519
%  Dissolve interpolation.
520
%
521
    elseif ( s_eqi ( word_one, 'D_INTERP' ) )
522
%
523
%  DEG
524
%  Degree.
525
%
526
    elseif ( s_eqi ( word_one, 'DEG' ) )
527
%
528
%  END
529
%  End statement.
530
%
531
    elseif ( s_eqi ( word_one, 'END' ) )
532
%
533
%  F V1 V2 V3 ...
534
%    or
535
%  F V1/VT1/VN1 V2/VT2/VN2 ...
536
%    or
537
%  F V1//VN1 V2//VN2 ...
538
%
539
%  Face.
540
%  A face is defined by the vertices.
541
%  Optionally, slashes may be used to include the texture vertex
542
%  and vertex normal indices.
543
%
544
    elseif ( s_eqi ( word_one, 'F' ) )
545
546
      face = face + 1;
547
548
      vertex = 0;
549
550
      while ( 1 )
551
552
        [ word, done ] = word_next_read ( text, done );
553
554
        if ( done )
555
          break
556
        end
557
558
        vertex = vertex + 1;
559
        order_max = max ( order_max, vertex );
560
%
561
%  Locate the slash characters in the word, if any.
562
%
563
        i1 = ch_index ( word, '/' );
564
        if ( 0 < i1 )
565
          i2 = ch_index ( word(i1+1), '/' ) + i1;
566
        else
567
          i2 = 0;
568
        end
569
%
570
%  Read the vertex index.
571
%
572
        itemp = s_to_i4 ( word );
573
574
        face_node(vertex,face) = itemp;
575
        face_order(face) = face_order(face) + 1;
576
%
577
%  If there are two slashes, then read the data following the second one.
578
%
579
        if ( 0 < i2 )
580
581
          itemp = s_to_i4 ( word(i2+1) );
582
583
          vertex_normal(vertex,face) = itemp;
584
585
        end
586
587
      end
588
%
589
%  G
590
%  Group name.
591
%
592
    elseif ( s_eqi ( word_one, 'G' ) )
593
%
594
%  HOLE
595
%  Inner trimming loop.
596
%
597
    elseif ( s_eqi ( word_one, 'HOLE' ) )
598
%
599
%  L
600
%  A line, described by a sequence of vertex indices.
601
%  Are the vertex indices 0 based or 1 based?
602
%
603
    elseif ( s_eqi ( word_one, 'L' ) )
604
%
605
%  LOD
606
%  Level of detail.
607
%
608
    elseif ( s_eqi ( word_one, 'LOD' ) )
609
%
610
%  MG
611
%  Merging group.
612
%
613
    elseif ( s_eqi ( word_one, 'MG' ) )
614
%
615
%  MTLLIB
616
%  Material library.
617
%
618
    elseif ( s_eqi ( word_one, 'MTLLIB' ) )
619
%
620
%  O
621
%  Object name.
622
%
623
    elseif ( s_eqi ( word_one, 'O' ) )
624
%
625
%  P
626
%  Point.
627
%
628
    elseif ( s_eqi ( word_one, 'P' ) )
629
%
630
%  PARM
631
%  Parameter values.
632
%
633
    elseif ( s_eqi ( word_one, 'PARM' ) )
634
%
635
%  S
636
%  Smoothing group.
637
%
638
    elseif ( s_eqi ( word_one, 'S' ) )
639
%
640
%  SCRV
641
%  Special curve.
642
%
643
    elseif ( s_eqi ( word_one, 'SCRV' ) )
644
%
645
%  SHADOW_OBJ
646
%  Shadow casting.
647
%
648
    elseif ( s_eqi ( word_one, 'SHADOW_OBJ' ) )
649
%
650
%  SP
651
%  Special point.
652
%
653
    elseif ( s_eqi ( word_one, 'SP' ) )
654
%
655
%  STECH
656
%  Surface approximation technique.
657
%
658
    elseif ( s_eqi ( word_one, 'STECH' ) )
659
%
660
%  STEP
661
%  Stepsize.
662
%
663
    elseif ( s_eqi ( word_one, 'STEP' ) )
664
%
665
%  SURF
666
%  Surface.
667
%
668
    elseif ( s_eqi ( word_one, 'SURF' ) )
669
%
670
%  TRACE_OBJ
671
%  Ray tracing.
672
%
673
    elseif ( s_eqi ( word_one, 'TRACE_OBJ' ) )
674
%
675
%  TRIM
676
%  Outer trimming loop.
677
%
678
    elseif ( s_eqi ( word_one, 'TRIM' ) )
679
%
680
%  USEMTL
681
%  Material name.
682
%
683
    elseif ( s_eqi ( word_one, 'USEMTL' ) )
684
%
685
%  V X Y Z
686
%  Geometric vertex.
687
%
688
    elseif ( s_eqi ( word_one, 'V' ) )
689
690
      node = node + 1;
691
692
      for i = 1 : 3
693
        [ word, done ] = word_next_read ( text, done );
694
        temp = s_to_r8 ( word );
695
        node_xyz(i,node) = temp;
696
      end
697
%
698
%  VN
699
%  Vertex normals.
700
%
701
    elseif ( s_eqi ( word_one, 'VN' ) )
702
703
      normal = normal + 1;
704
705
      for i = 1 : 3
706
        [ word, done ] = word_next_read ( text, done );
707
        temp = s_to_r8 ( word );
708
        normal_vector(i,normal) = temp;
709
      end
710
%
711
%  VT
712
%  Vertex texture.
713
%
714
    elseif ( s_eqi ( word_one, 'VT' ) )
715
%
716
%  VP
717
%  Parameter space vertices.
718
%
719
    elseif ( s_eqi ( word_one, 'VP' ) )
720
%
721
%  Unrecognized keyword.
722
%
723
    else
724
725
    end
726
727
  end
728
729
  fclose ( input_file_unit );
730
731
  return
732
end
733
function [ node_num, face_num, normal_num, order_max ] = obj_size ( ...
734
  input_file_name )
735
736
%*****************************************************************************80
737
%
738
%% OBJ_SIZE determines sizes of graphics objects in an Alias OBJ file.
739
%
740
%  Discussion:
741
%
742
%    The only items of interest to this routine are vertices,
743
%    faces, and normal vectors.
744
%
745
%  Example:
746
%
747
%    #  magnolia.obj
748
%
749
%    v -3.269770 -39.572201 0.876128
750
%    v -3.263720 -39.507999 2.160890
751
%    ...
752
%    v 0.000000 -9.988540 0.000000
753
%
754
%    vn 1.0 0.0 0.0
755
%    ...
756
%    vn 0.0 1.0 0.0
757
%
758
%    f 8 9 11 10
759
%    f 12 13 15 14
760
%    ...
761
%    f 788 806 774
762
%
763
%  Licensing:
764
%
765
%    This code is distributed under the GNU LGPL license.
766
%
767
%  Modified:
768
%
769
%    26 September 2008
770
%
771
%  Author:
772
%
773
%    John Burkardt
774
%
775
%  Parameters:
776
%
777
%    Input, string INPUT_FILE_NAME, the input file name.
778
%
779
%    Output, integer NODE_NUM, the number of points.
780
%
781
%    Output, integer FACE_NUM, the number of faces.
782
%
783
%    Output, integer NORMAL_NUM, the number of normal vectors.
784
%
785
%    Output, integer ORDER_MAX, the maximum face order.
786
%
787
  face_num = 0;
788
  node_num = 0;
789
  normal_num = 0;
790
  order_max = 0;
791
  text_num = 0;
792
%
793
%  If no file input, try to get one from the user.
794
%
795
  if ( nargin < 1 )
796
    input_file_name = input ( 'Enter the name of the ASCII OBJ file.' );
797
    if ( isempty ( input_file_name ) )
798
      return
799
    end
800
  end
801
%
802
%  Open the file.
803
%
804
  input_file_unit = fopen ( input_file_name, 'r' );
805
806
  if ( input_file_unit < 0 )
807
    fprintf ( 1, '\n' );
808
    fprintf ( 1, 'OBJ_SIZE - Fatal error!\n' );
809
    fprintf ( 1, '  Could not open the file "%s".\n', input_file_name );
810
    error ( 'OBJ_SIZE - Fatal error!' );
811
  end
812
%
813
%  Read a line of text from the file.
814
%
815
  while ( 1 )
816
817
    text = fgetl ( input_file_unit );
818
819
    if ( text == -1 )
820
      break
821
    end
822
823
    text_num = text_num + 1;
824
%
825
%  Replace any control characters (in particular, TABs) by blanks.
826
%
827
    s_control_blank ( text );
828
829
    done = 1;
830
    word_index = 0;
831
%
832
%  Read a word from the line.
833
%
834
    [ word, done ] = word_next_read ( text, done );
835
%
836
%  If no more words in this line, read a new line.
837
%
838
    if ( done )
839
      continue
840
    end
841
%
842
%  If this word begins with '#' or '$', then it is a comment.  Read a new line.
843
%
844
    if ( word(1) == '#' || word(1) == '$' )
845
      continue
846
    end
847
848
    word_index = word_index + 1;
849
850
    if ( word_index == 1 )
851
      word_one = word;
852
    end
853
%
854
%  F V1 V2 V3 ...
855
%    or
856
%  F V1/VT1/VN1 V2/VT2/VN2 ...
857
%    or
858
%  F V1//VN1 V2//VN2 ...
859
%
860
%  Face.
861
%  A face is defined by the vertices.
862
%  Optionally, slashes may be used to include the texture vertex
863
%  and vertex normal indices.
864
%
865
    if ( s_eqi ( word_one, 'F' ) )
866
867
      face_num = face_num + 1;
868
869
      vertex = 0;
870
871
      while ( 1 )
872
873
        [ word, done ] = word_next_read ( text, done );
874
875
        if ( done )
876
          break
877
        end
878
879
        vertex = vertex + 1;
880
        order_max = max ( order_max, vertex );
881
%
882
%  Locate the slash characters in the word, if any.
883
%
884
        i1 = ch_index ( word, '/' );
885
        if ( 0 < i1 )
886
          i2 = ch_index ( word(i1+1), '/' ) + i1;
887
        else
888
          i2 = 0;
889
        end
890
%
891
%  Read the vertex index.
892
%
893
        s_to_i4 ( word );
894
%
895
%  If there are two slashes, then read the data following the second one.
896
%
897
        if ( 0 < i2 )
898
          s_to_i4 ( word(i2+1) );
899
        end
900
901
      end
902
%
903
%  V X Y Z W
904
%  Geometric vertex.
905
%
906
    elseif ( s_eqi ( word_one, 'V' ) )
907
908
      node_num = node_num + 1;
909
      continue
910
%
911
%  VN
912
%  Vertex normals.
913
%
914
    elseif ( s_eqi ( word_one, 'VN' ) )
915
916
      normal_num = normal_num + 1;
917
      continue
918
919
    end
920
921
  end
922
923
  fclose ( input_file_unit );
924
925
  return
926
end
927
function obj_size_print ( input_file_name, node_num, face_num, normal_num, ...
928
  order_max )
929
930
%*****************************************************************************80
931
%
932
%% OBJ_SIZE_PRINT prints sizes associated with an OBJ file.
933
%
934
%  Licensing:
935
%
936
%    This code is distributed under the GNU LGPL license.
937
%
938
%  Modified:
939
%
940
%    26 September 2008
941
%
942
%  Author:
943
%
944
%    John Burkardt
945
%
946
%  Parameters:
947
%
948
%    Input, string INPUT_FILE_NAME, the name of the input file.
949
%
950
%    Input, integer NODE_NUM, the number of vertices defined.
951
%
952
%    Input, integer FACE_NUM, the number of faces defined.
953
%
954
%    Input, integer NORMAL_NUM, the number of normal vectors defined.
955
%
956
%    Input, integer ORDER_MAX, the maximum number of vertices per face.
957
%
958
  fprintf ( 1, '\n' );
959
  fprintf ( 1, '  Object sizes for OBJ file "%s":\n', input_file_name );
960
  fprintf ( 1, '\n' );
961
  fprintf ( 1, '  Nodes              = %d\n', node_num );
962
  fprintf ( 1, '  Faces              = %d\n', face_num );
963
  fprintf ( 1, '  Maximum face order = %d\n', order_max );
964
  fprintf ( 1, '  Normal vectors     = %d\n', normal_num );
965
966
  return
967
end
968
function s = s_control_blank ( s )
969
970
%*****************************************************************************80
971
%
972
%% S_CONTROL_BLANK replaces control characters with blanks.
973
%
974
%  Discussion:
975
%
976
%    A "control character" has ASCII code <= 31 or 127 <= ASCII code.
977
%
978
%  Licensing:
979
%
980
%    This code is distributed under the GNU LGPL license.
981
%
982
%  Modified:
983
%
984
%    27 September 2008
985
%
986
%  Author:
987
%
988
%    John Burkardt
989
%
990
%  Parameters:
991
%
992
%    Input/output, string S, the string to be transformed.
993
%
994
  s_length = s_len_trim ( s );
995
996
  for i = 1 : s_length
997
    if ( ch_is_control ( s(i) ) )
998
      s(i) = ' ';
999
    end
1000
  end
1001
1002
  return
1003
end
1004
function value = s_eqi ( s1, s2 )
1005
1006
%*****************************************************************************80
1007
%
1008
%% S_EQI is a case insensitive comparison of two strings for equality.
1009
%
1010
%  Example:
1011
%
1012
%    S_EQI ( 'Anjana', 'ANJANA' ) is TRUE.
1013
%
1014
%  Licensing:
1015
%
1016
%    This code is distributed under the GNU LGPL license.
1017
%
1018
%  Modified:
1019
%
1020
%    30 April 2004
1021
%
1022
%  Author:
1023
%
1024
%    John Burkardt
1025
%
1026
%  Parameters:
1027
%
1028
%    Input, string S1, S2, the strings to compare.
1029
%
1030
%    Output, logical VALUE, is TRUE if the strings are equal.
1031
%
1032
  FALSE = 0;
1033
  TRUE = 1;
1034
1035
  len1 = length ( s1 );
1036
  len2 = length ( s2 );
1037
  lenc = min ( len1, len2 );
1038
1039
  for i = 1 : lenc
1040
1041
    c1 = ch_cap ( s1(i) );
1042
    c2 = ch_cap ( s2(i) );
1043
1044
    if ( c1 ~= c2 )
1045
      value = FALSE;
1046
      return
1047
    end
1048
1049
  end
1050
1051
  for i = lenc + 1 : len1
1052
    if ( s1(i) ~= ' ' )
1053
      value = FALSE;
1054
      return
1055
    end
1056
  end
1057
1058
  for i = lenc + 1 : len2
1059
    if ( s2(i) ~= ' ' )
1060
      value = FALSE;
1061
      return
1062
    end
1063
  end
1064
1065
  value = TRUE;
1066
1067
  return
1068
end
1069
function s2 = s_escape_tex ( s1 )
1070
1071
%*****************************************************************************80
1072
%
1073
%% S_ESCAPE_TEX de-escapes TeX escape sequences.
1074
%
1075
%  Discussion:
1076
%
1077
%    In particular, every occurrence of the characters '\', '_',
1078
%    '^', '{' and '}' will be replaced by '\\', '\_', '\^',
1079
%    '\{' and '\}'.  A TeX interpreter, on seeing these character
1080
%    strings, is then likely to return the original characters.
1081
%
1082
%  Licensing:
1083
%
1084
%    This code is distributed under the GNU LGPL license.
1085
%
1086
%  Modified:
1087
%
1088
%    19 January 2007
1089
%
1090
%  Author:
1091
%
1092
%    John Burkardt
1093
%
1094
%  Parameters:
1095
%
1096
%    Input, string S1, the string to be de-escaped.
1097
%
1098
%    Output, string S2, a copy of the string, modified to avoid TeX escapes.
1099
%
1100
  s1_length = length ( s1 );
1101
1102
  s1_pos = 0;
1103
  s2_pos = 0;
1104
  s2 = [];
1105
1106
  while ( s1_pos < s1_length )
1107
1108
    s1_pos = s1_pos + 1;
1109
1110
    if ( s1(s1_pos) == '\' || ...
1111
         s1(s1_pos) == '_' || ...
1112
         s1(s1_pos) == '^' || ...
1113
         s1(s1_pos) == '{' || ...
1114
         s1(s1_pos) == '}' )
1115
      s2_pos = s2_pos + 1;
1116
      s2 = strcat ( s2, '\' );
1117
    end
1118
1119
    s2_pos = s2_pos + 1;
1120
    s2 = strcat ( s2, s1(s1_pos) );
1121
1122
  end
1123
1124
  return
1125
end
1126
function len = s_len_trim ( s )
1127
1128
%*****************************************************************************80
1129
%
1130
%% S_LEN_TRIM returns the length of a character string to the last nonblank.
1131
%
1132
%  Licensing:
1133
%
1134
%    This code is distributed under the GNU LGPL license.
1135
%
1136
%  Modified:
1137
%
1138
%    14 June 2003
1139
%
1140
%  Author:
1141
%
1142
%    John Burkardt
1143
%
1144
%  Parameters:
1145
%
1146
%    Input, string S, the string to be measured.
1147
%
1148
%    Output, integer LEN, the length of the string up to the last nonblank.
1149
%
1150
  len = length ( s );
1151
1152
  while ( 0 < len )
1153
    if ( s(len) ~= ' ' )
1154
      return
1155
    end
1156
    len = len - 1;
1157
  end
1158
1159
  return
1160
end
1161
function ival = s_to_i4 ( s )
1162
1163
%*****************************************************************************80
1164
%
1165
%% S_TO_I4 reads an integer value from a string.
1166
%
1167
%  Licensing:
1168
%
1169
%    This code is distributed under the GNU LGPL license.
1170
%
1171
%  Modified:
1172
%
1173
%    18 November 2003
1174
%
1175
%  Author:
1176
%
1177
%    John Burkardt
1178
%
1179
%  Parameters:
1180
%
1181
%    Input, string S, a string to be examined.
1182
%
1183
%    Output, integer IVAL, the integer value read from the string.
1184
%
1185
  sgn = 1;
1186
  state = 0;
1187
  ival = 0;
1188
1189
  i = 0;
1190
1191
  while ( i < s_len_trim ( s ) )
1192
1193
    i = i + 1;
1194
    c = s(i);
1195
1196
    if ( state == 0 )
1197
1198
      if ( c == ' ' )
1199
1200
      elseif ( c == '-' )
1201
        state = 1;
1202
        sgn = -1;
1203
      elseif ( c == '+' )
1204
        state = 1;
1205
        sgn = +1;
1206
      elseif ( '0' <= c && c <= '9' )
1207
        state = 2;
1208
        ival = c - '0';
1209
      else
1210
        fprintf ( '\n' );
1211
        fprintf ( 'S_TO_I4 - Fatal error!\n' );
1212
        fprintf ( '  Illegal character %c while in state %d.\n', c, state );
1213
        return;
1214
      end
1215
%
1216
%  Have read the sign, now expecting the first digit.
1217
%
1218
    elseif ( state == 1 )
1219
1220
      if ( c == ' ' )
1221
1222
      elseif ( '0' <= c && c <= '9' )
1223
        state = 2;
1224
        ival = c - '0';
1225
      else
1226
        fprintf ( '\n' );
1227
        fprintf ( 'S_TO_I4 - Fatal error!\n' );
1228
        fprintf ( '  Illegal character %c while in state %d.\n', c, state );
1229
        return
1230
      end
1231
%
1232
%  Have read at least one digit, expecting more.
1233
%
1234
    elseif ( state == 2 )
1235
1236
      if ( '0' <= c && c <= '9' )
1237
        ival = 10 * ival + c - '0';
1238
      else
1239
        ival = sgn * ival;
1240
        return;
1241
      end
1242
1243
    end
1244
1245
  end
1246
%
1247
%  If we read all the characters in the string, see if we're OK.
1248
%
1249
  if ( state ~= 2 )
1250
    fprintf ( '\n' );
1251
    fprintf ( 'S_TO_I4 - Fatal error!\n' );
1252
    fprintf ( '  Did not read enough information to define an integer!\n' );
1253
    return;
1254
  end
1255
1256
  ival = sgn * ival;
1257
1258
  return
1259
end
1260
function [ r, lchar, ierror ] = s_to_r8 ( s )
1261
1262
%*****************************************************************************80
1263
%
1264
%% S_TO_R8 reads an R8 from a string.
1265
%
1266
%  Discussion:
1267
%
1268
%    This routine will read as many characters as possible until it reaches
1269
%    the end of the string, or encounters a character which cannot be
1270
%    part of the real number.
1271
%
1272
%    Legal input is:
1273
%
1274
%       1 blanks,
1275
%       2 '+' or '-' sign,
1276
%       2.5 spaces
1277
%       3 integer part,
1278
%       4 decimal point,
1279
%       5 fraction part,
1280
%       6 'E' or 'e' or 'D' or 'd', exponent marker,
1281
%       7 exponent sign,
1282
%       8 exponent integer part,
1283
%       9 exponent decimal point,
1284
%      10 exponent fraction part,
1285
%      11 blanks,
1286
%      12 final comma or semicolon.
1287
%
1288
%    with most quantities optional.
1289
%
1290
%  Example:
1291
%
1292
%    S                 R
1293
%
1294
%    '1'               1.0
1295
%    '     1   '       1.0
1296
%    '1A'              1.0
1297
%    '12,34,56'        12.0
1298
%    '  34 7'          34.0
1299
%    '-1E2ABCD'        -100.0
1300
%    '-1X2ABCD'        -1.0
1301
%    ' 2E-1'           0.2
1302
%    '23.45'           23.45
1303
%    '-4.2E+2'         -420.0
1304
%    '17d2'            1700.0
1305
%    '-14e-2'         -0.14
1306
%    'e2'              100.0
1307
%    '-12.73e-9.23'   -12.73 * 10.0**(-9.23)
1308
%
1309
%  Licensing:
1310
%
1311
%    This code is distributed under the GNU LGPL license.
1312
%
1313
%  Modified:
1314
%
1315
%    22 November 2003
1316
%
1317
%  Author:
1318
%
1319
%    John Burkardt
1320
%
1321
%  Parameters:
1322
%
1323
%    Input, string S, the string containing the
1324
%    data to be read.  Reading will begin at position 1 and
1325
%    terminate at the end of the string, or when no more
1326
%    characters can be read to form a legal real.  Blanks,
1327
%    commas, or other nonnumeric data will, in particular,
1328
%    cause the conversion to halt.
1329
%
1330
%    Output, real R, the value that was read from the string.
1331
%
1332
%    Output, integer LCHAR, the number of characters of S that were used to form R.
1333
%
1334
%    Output, integer IERROR, is 0 if no error occurred.
1335
%
1336
  s_length = s_len_trim ( s );
1337
  ierror = 0;
1338
  lchar = -1;
1339
  isgn = 1;
1340
  rtop = 0.0;
1341
  rbot = 1.0;
1342
  jsgn = 1;
1343
  jtop = 0;
1344
  jbot = 1;
1345
  ihave = 1;
1346
  iterm = 0;
1347
1348
  while ( 1 )
1349
1350
    lchar = lchar + 1;
1351
    c = s(lchar+1);
1352
%
1353
%  Blank character.
1354
%
1355
    if ( c == ' ' )
1356
1357
      if ( ihave == 2 )
1358
1359
      elseif ( ihave == 6 || ihave == 7 )
1360
        iterm = 1;
1361
      elseif ( 1 < ihave )
1362
        ihave = 11;
1363
      end
1364
%
1365
%  Comma.
1366
%
1367
    elseif ( c == ',' || c == ';' )
1368
1369
      if ( ihave ~= 1 )
1370
        iterm = 1;
1371
        ihave = 12;
1372
        lchar = lchar + 1;
1373
      end
1374
%
1375
%  Minus sign.
1376
%
1377
    elseif ( c == '-' )
1378
1379
      if ( ihave == 1 );
1380
        ihave = 2;
1381
        isgn = -1;
1382
      elseif ( ihave == 6 )
1383
        ihave = 7;
1384
        jsgn = -1;
1385
      else
1386
        iterm = 1;
1387
      end
1388
%
1389
%  Plus sign.
1390
%
1391
    elseif ( c == '+' )
1392
1393
      if ( ihave == 1 )
1394
        ihave = 2;
1395
      elseif ( ihave == 6 )
1396
        ihave = 7;
1397
      else
1398
        iterm = 1;
1399
      end
1400
%
1401
%  Decimal point.
1402
%
1403
    elseif ( c == '.' )
1404
1405
      if ( ihave < 4 )
1406
        ihave = 4;
1407
      elseif ( 6 <= ihave && ihave <= 8 )
1408
        ihave = 9;
1409
      else
1410
        iterm = 1;
1411
      end
1412
%
1413
%  Exponent marker.
1414
%
1415
    elseif ( ch_eqi ( c, 'E' ) || ch_eqi ( c, 'D' ) )
1416
1417
      if ( ihave < 6 )
1418
        ihave = 6;
1419
      else
1420
        iterm = 1;
1421
      end
1422
%
1423
%  Digit.
1424
%
1425
    elseif ( ihave < 11 && ch_is_digit ( c ) )
1426
1427
      if ( ihave <= 2 )
1428
        ihave = 3;
1429
      elseif ( ihave == 4 )
1430
        ihave = 5;
1431
      elseif ( ihave == 6 || ihave == 7 )
1432
        ihave = 8;
1433
      elseif ( ihave == 9 )
1434
        ihave = 10;
1435
      end
1436
1437
      d = ch_to_digit ( c );
1438
1439
      if ( ihave == 3 )
1440
        rtop = 10.0 * rtop + d;
1441
      elseif ( ihave == 5 )
1442
        rtop = 10.0 * rtop + d;
1443
        rbot = 10.0 * rbot;
1444
      elseif ( ihave == 8 )
1445
        jtop = 10 * jtop + d;
1446
      elseif ( ihave == 10 )
1447
        jtop = 10 * jtop + d;
1448
        jbot = 10 * jbot;
1449
      end
1450
%
1451
%  Anything else is regarded as a terminator.
1452
%
1453
    else
1454
      iterm = 1;
1455
    end
1456
%
1457
%  If we haven't seen a terminator, and we haven't examined the
1458
%  entire string, go get the next character.
1459
%
1460
    if ( iterm == 1 || s_length <= lchar + 1 )
1461
      break;
1462
    end
1463
1464
  end
1465
%
1466
%  If we haven't seen a terminator, and we have examined the
1467
%  entire string, then we're done, and LCHAR is equal to S_LENGTH.
1468
%
1469
  if ( iterm ~= 1 && lchar + 1 == s_length )
1470
    lchar = s_length;
1471
  end
1472
%
1473
%  Number seems to have terminated.  Have we got a legal number?
1474
%  Not if we terminated in states 1, 2, 6 or 7!
1475
%
1476
  if ( ihave == 1 || ihave == 2 || ihave == 6 || ihave == 7 )
1477
    fprintf ( 1, '\n' );
1478
    fprintf ( 1, 'S_TO_R8 - Fatal error!\n' );
1479
    fprintf ( 1, '  IHAVE = %d\n', ihave );
1480
    error ( 'S_TO_R8 - Fatal error!' );
1481
  end
1482
%
1483
%  Number seems OK.  Form it.
1484
%
1485
  if ( jtop == 0 )
1486
    rexp = 1.0;
1487
  else
1488
1489
    if ( jbot == 1 )
1490
      rexp = 10.0^( jsgn * jtop );
1491
    else
1492
      rexp = jsgn * jtop;
1493
      rexp = rexp / jbot;
1494
      rexp = 10.0^rexp;
1495
    end
1496
1497
  end
1498
1499
  r = isgn * rexp * rtop / rbot;
1500
1501
  return
1502
end
1503
function timestamp ( )
1504
1505
%*****************************************************************************80
1506
%
1507
%% TIMESTAMP prints the current YMDHMS date as a timestamp.
1508
%
1509
%  Licensing:
1510
%
1511
%    This code is distributed under the GNU LGPL license.
1512
%
1513
%  Modified:
1514
%
1515
%    14 February 2003
1516
%
1517
%  Author:
1518
%
1519
%    John Burkardt
1520
%
1521
  t = now;
1522
  c = datevec ( t );
1523
  s = datestr ( c, 0 );
1524
  fprintf ( 1, '%s\n', s );
1525
1526
  return
1527
end
1528
function [ word, done ] = word_next_read ( s, done )
1529
1530
%*****************************************************************************80
1531
%
1532
%% WORD_NEXT_READ "reads" words from a string, one at a time.
1533
%
1534
%  Special cases:
1535
%
1536
%    The following characters are considered to be a single word,
1537
%    whether surrounded by spaces or not:
1538
%
1539
%      " ( ) { } [ ]
1540
%
1541
%    Also, if there is a trailing comma on the word, it is stripped off.
1542
%    This is to facilitate the reading of lists.
1543
%
1544
%  Licensing:
1545
%
1546
%    This code is distributed under the GNU LGPL license.
1547
%
1548
%  Modified:
1549
%
1550
%    24 September 2005
1551
%
1552
%  Author:
1553
%
1554
%    John Burkardt
1555
%
1556
%  Parameters:
1557
%
1558
%    Input, string S, a string, presumably containing words
1559
%    separated by spaces.
1560
%
1561
%    Input, logical DONE.
1562
%    TRUE, if we are beginning a new string;
1563
%    FALSE, if we are continuing to process the current string.
1564
%
1565
%    Output, string WORD.
1566
%    If DONE is FALSE, then WORD contains the "next" word read.
1567
%    If DONE is TRUE, then WORD is blank, because there was no more to read.
1568
%
1569
%    Output, logical DONE.
1570
%      FALSE if another word was read,
1571
%      TRUE if no more words could be read.
1572
%
1573
  persistent lenc;
1574
  persistent next;
1575
  
1576
  tab = char ( 9 );
1577
%
1578
%  We "remember" LENC and NEXT from the previous call.
1579
%
1580
%  An input value of DONE = TRUE signals a new line of text to examine.
1581
%
1582
  if ( done )
1583
1584
    next = 1;
1585
    done = 0;
1586
    lenc = s_len_trim ( s );
1587
1588
    if ( lenc <= 0 )
1589
      done = 1;
1590
      word = ' ';
1591
      return
1592
    end
1593
1594
  end
1595
%
1596
%  Beginning at index NEXT, search the string for the next nonblank,
1597
%  which signals the beginning of a word.
1598
%
1599
  ilo = next;
1600
%
1601
%  ...S(NEXT:) is blank.  Return with WORD = ' ' and DONE = TRUE.
1602
%
1603
  while ( 1 )
1604
1605
    if ( lenc < ilo )
1606
      word = ' ';
1607
      done = 1;
1608
      next = lenc + 1;
1609
      return
1610
    end
1611
%
1612
%  If the current character is blank, skip to the next one.
1613
%
1614
    if ( s(ilo) ~= ' ' && s(ilo) ~= tab )
1615
      break
1616
    end
1617
1618
    ilo = ilo + 1;
1619
1620
  end
1621
%
1622
%  ILO is the index of the next nonblank character in the string.
1623
%
1624
%  If this initial nonblank is a special character,
1625
%  then that's the whole word as far as we're concerned,
1626
%  so return immediately.
1627
%
1628
  if ( s(ilo) == '"' || ...
1629
       s(ilo) == '(' || ...
1630
       s(ilo) == ')' || ...
1631
       s(ilo) == '{' || ...
1632
       s(ilo) == '}' || ...
1633
       s(ilo) == '[' || ...
1634
       s(ilo) == ']' )
1635
1636
    word = s(ilo);
1637
    next = ilo + 1;
1638
    return
1639
1640
  end
1641
%
1642
%  Now search for the last contiguous character that is not a
1643
%  blank, TAB, or special character.
1644
%
1645
  next = ilo + 1;
1646
1647
  while ( next <= lenc )
1648
1649
    if ( s(next) == ' ' )
1650
      break;
1651
    elseif ( s(next) == tab )
1652
      break;
1653
    elseif ( s(next) == '"' )
1654
      break;
1655
    elseif ( s(next) == '(' )
1656
      break;
1657
    elseif ( s(next) == ')' )
1658
      break;
1659
    elseif ( s(next) == '{' )
1660
      break;
1661
    elseif ( s(next) == '}' )
1662
      break;
1663
    elseif ( s(next) == '[' )
1664
      break;
1665
    elseif ( s(next) == ']' )
1666
      break;
1667
    end
1668
1669
    next = next + 1;
1670
1671
  end
1672
1673
  if ( s(next-1) == ',' ) 
1674
    word = s(ilo:next-2);
1675
  else
1676
    word = s(ilo:next-1);
1677
  end
1678
1679
  return
1680
end