smoother gears
Trying to get a smoother appearance for the curved gear teeth involves lessons both in logo programming and in the underlying 3d display technology.
The first requirement is to use a graphics option for the generated object which is not directly supported by vrmath2 but can be invoked anyways. It is the x3d creaseAngle field which does not show up in the object inspector but can be set using the set command.
The second requirement is that adjacent facets need to share their corner points and not use duplicated points which is the default behaviour. Since facets are defined by a set of indices pointing to point coordinates, this means that adjacent facets need to use the same indices for shared points.
It is possible to retrieve and reset the indices of an object after manipulating them. It turns out that the list of indices is delivered as a long string which logo does not natively deal well with. So it became necessary to convert the long string into a logo list (and the list to a logo array) which required more in depth logo programming.
Here are the changed procedures (without a lot of comments)
TO fence :positions :width PU SETPOS FIRST :positions FACE PCOFF PD SHOW REDUCE "quads :positions PU ;share indices for smooth shading LOCALMAKE "obj_face WORD OBJECT "_face SET :obj_face "coordindex (mergeindices GET :obj_face "coordindex) ; hey this works after saving and loading the scene SET :obj_face "creaseAngle 3.14 LINE END TO mergeindices :indices LOCALMAKE "iarr LISTTOARRAY wordstolist :indices LOCALMAKE "i 1 LOCALMAKE "s 0 LOCAL "i1 WHILE (:i < COUNT :iarr) [ ;skip first segment IF NOTEQUALP :s 0 [ MAKE "i1 ITEM :i :iarr ;this is the actual index sharing SETITEM :i :iarr (:i1 - 1) SETITEM (:i + 1) :iarr (:i1 - 2) ] MAKE "s :s + 1 IF EQUALP :s :fsegments [ MAKE "s 0 ] MAKE "i :i + 5 ] ;merge vertical LOCALMAKE "s5 :fsegments * 5 ;skip first row FOR [i (:s5 + 1) COUNT :iarr :s5] [ ;go through segments FOR [j 0 (:fsegments - 1)] [ ;lookup index from previous segment MAKE "i1 (ITEM ((:i + :j * 5) - :s5 + 1) :iarr) SETITEM (:i + :j * 5) :iarr :i1 MAKE "i1 (ITEM ((:i + :j * 5) + 3 - :s5 - 1) :iarr) SETITEM (:i + :j * 5 + 3) :iarr :i1 ] ] OUTPUT listtowords ARRAYTOLIST :iarr END TO wordstolist :words ;butfirst does not work with strings ;so recursive does not work ;(show first butfirst :words :list) ;if emptyp :words [output :list] ;if equalp ascii :words 32 ; [output wordtolist butfirst :words lput first butfirst :words :list] ; (show word last :list first :words) ;output wordtolist butfirst :words lput (word last :list first :words) butlast :list LOCALMAKE "wlist [] LOCALMAKE "cword " LOCAL "i FOR [i 0 ((COUNT :words) - 1)] [ IFELSE EQUALP ASCII ITEM :i :words 32 [ QUEUE "wlist :cword MAKE "cword "] [ MAKE "cword WORD :cword ITEM :i :words ] ] ;show :i IF NOTEQUALP ASCII ITEM :i :words 32 [QUEUE "wlist :cword] OUTPUT :wlist END TO listtowords :wlist OUTPUT APPLY "word (MAP "addspace :wlist) END TO addspace :w OUTPUT WORD :w CHAR 32 END
It is great to see that this actually works as intended. Next would be to also share indices "vertically", see below. A more general solution involves finding which points are duplicated, finding the indices pointing to the duplicated points, and then replacing these indices with the index pointing to the first point. In a first round this would not remove any coordinates. If this works it would be possible then to remove the duplicated coordinates and adjust the indices. This could work one by one, eg. after removing one point all indices larger than the one pointing to the removed point are decremented by one (except for the minus ones).
Update: really smooth now after I thought about the vertical merging as well. The logo has it as a second merge.
In the end, for this application, it may be easiest to just recreate the point list and the index list from scratch. The point list is easy, it is the gear profile, offset along the z axis as many times as requested. The index list also could be constructed since the order of the points is known. To start just a small face object is needed so it may speed up the logo execution as well. The turtle could rest for a while as well.
- aplesch's blog
- Login or register to post comments
- 4068 reads
Comments
Nice and smooth
Wow you did it and the codes are quite succint.
I noticed that creaseAngle did not show in DOM but can be added and does have effect.. Is this intentional by x3dom or an oversight?
strings
fieldChanged() for IndexedFaceSet would be the place to check if changing the creaseAngle is implemented. Changing it requires remeshing so perhaps it is intentionally not implemented ?
The hardest part was to figure out how to deal with strings since according to the manual most data selectors only work on lists or arrays. Luckily item works on strings. Also spaces in strings are a little harder. The only way I could figure out how to indicate a space character was with ascii and char.
ascii & char
I think it is very clever that you use ascii & char. :-) I still have some trouble sometimes using Logo data types with data selectors. The template-based iteration seems to be powerful. I wonder if javascript has similar counterparts.
I did not use the fieldChanged method to check, but when implementing the SET command, I think I check first whether the node has the attribute to be set. Since SET works for creaseAngle, which means that it is implemented (or at least declared as an attribute). I am just curious why it did not show in DOM by default when dumping the indexedfaceset node (as in the Object Setting tab).
github
Sorry, I meant to check what the implementation of fieldChanged() as available on github actually does. If it tries to do something with creaseAngle it may be a bug, if it does not it may be intentional (or an oversight).
javascript has similar functions such map, apply, reduce (I think). They are considered more advanced usage but I think it is more a matter of thinking in a more functional programming style.
intentional
It looks like x3dom just does not implement DOM updates after creaseAgnle is changed. The debug log is supposed to show a warning that it is not implemented.