On 9/22/2018 3:41 PM, Alan Braslau wrote:
On Sat, 22 Sep 2018 13:45:17 +0200
Hans Hagen <j.ha...@xs4all.nl> wrote:

On 9/22/2018 12:08 PM, Floris van Manen wrote:
It does not seem to work for all character combinations.
e.g. B&T works, C&T works, C&M works, but N&T does not work.
not N&M
Why would that be?
Thanks
.Floris




On 22 Sep 2018, at 11:27, Hans Hagen <j.ha...@xs4all.nl
<mailto:j.ha...@xs4all.nl>> wrote:

On 9/22/2018 10:35 AM, Henri Menke wrote:
Dear list,
Challanged by a very old TeX.SX question
https://tex.stackexchange.com/questions/180510
I wanted to calculate all the intersection points between two
characters.  Therefore I ripped off the \showshape macro to load the
outlines from the font and convert them to MetaPost paths.  Then I try
to find all intersections by cutting the path.
It somewhat works but for some reason, in the MWE below two intersection
points are missing.  I also have the feeling that my implementation is
extremely inefficient.  I would very much appreciate some hints by the
MetaPost experts!
Cheers, Henri
---
\startluacode
-- That's a simple reimplemetation of the showshape macro
function outlinepaths(character)
     local fontid      = font.current()
     local shapedata   = fonts.hashes.shapes[fontid] -- by index
     local chardata    = fonts.hashes.characters[fontid] -- by unicode
     local shapeglyphs = shapedata.glyphs or { }
     character = utf.byte(character)
     local c = chardata[character]
     if c then
         if not c.index then
             return {}
         end
         local glyph = shapeglyphs[c.index]
         if glyph and (glyph.segments or glyph.sequence) then
             local units  = shapedata.units or 1000
             local factor = 100/units
             local paths  = fonts.metapost.paths(glyph,factor)
             return paths
         end
     end
end
\stopluacode
\def\mpdefineoutlines#1#2{\ctxlua{
     local char = "\luaescapestring{#1}"
     local outlines = outlinepaths("#2")
     local len = \letterhash outlines
     tex.print("path " .. char .. "[];")
     tex.print(char .. "n := " .. len .. ";")
     for i, path in ipairs(outlines) do
         tex.print(char .. "[" .. i .. "] := " .. path .. ";")
     end
   }}
\starttext
\startMPpage
pair shift; shift := (1cm,-1cm);
numeric angle; angle := 5;
\mpdefineoutlines{B}{B}
\mpdefineoutlines{T}{T}
nofill B2;
nofill B3;
eofill B1 withcolor .5[blue,white];
fill T1 shifted (shift) rotated (angle) withcolor .5[red,white];
path r;
numeric n; n := 0;
for i = 1 upto Bn:
     for j = 1 upto Tn:
         r := B[i];
         forever:
             pair q;
             r := r cutbefore (T[j] shifted (shift) rotated (angle));
             exitif length cuttings = 0;
             r := subpath(epsilon, length r) of r;
             q = point 0 of r;
             n := n + 1;
             dotlabel.urt(textext("\tfx" & decimal n), q);
         endfor;
     endfor ;
endfor ;
\stopMPpage
\stoptext

You migh find more when you go top double mode .. anyway, these
intersection calculations are not that accurate so you normally need
to apply some overkill.

- a bit cleaned up outlinepath function
- use document namespace
- add helper for defineoutline
- do 4 runs over the shapes (probably too many now)
- more neutral fill code

It makes a nice example for the metafun (although then I'd do it
slightly different). We need some rounding becaus eotherwise you get
similar points (you can add a message(q) someplace).

\startluacode

function document.outlinepaths(character)
    local chardata  = fonts.hashes.characters[true] -- by unicode
    local shapedata = fonts.hashes.shapes[true] -- by index
    local c         = chardata[character]
    if c and c.index and shapedata then
        local shapeglyphs = shapedata.glyphs or { }
        local glyph       = shapeglyphs[c.index]
        if glyph and (glyph.segments or glyph.sequence) then
            local units  = shapedata.units or 1000
            local factor = 100/units
            return fonts.metapost.paths(glyph,factor)
        end
    end
    return { }
end

function document.defineoutline(char,target)
    local outlines = document.outlinepaths(char)
    local nofpaths = #outlines
    context("path %s[] ;",target)
    context("numeric %sn ; %sn := %s ;",target,target,nofpaths)
    for i=1,nofpaths do
        context("%s[%i] := %s ; ",target,i,outlines[i])
    end
end
\stopluacode

\def\mpdefineoutlines#1#2{\ctxlua{document.defineoutline(\number`#1,"#2")}}

\starttext

\startMPpage
pair shift ; shift := (1cm,-1cm);
numeric angle ; angle := 5;

\mpdefineoutlines{B}{B}
\mpdefineoutlines{T}{T}

for i=1 upto Bn - 1 : nofill B[i] ; endfor ;
eofill B[Bn] withcolor .5[blue,white] ;

for i=1 upto Tn :
    T[i] := T[i] shifted shift rotated angle ;
endfor ;

for i=1 upto Tn - 1 : nofill T[i] ; endfor ;
eofill T[Tn] withcolor .5[red,white] ;

pair found[] ;
boolean isnew ;
numeric n ; n := 0 ;
pair rq ;

def GoForIt(expr how) =
    path r ;
    for i = 1 upto Bn :
        for j = 1 upto Tn :
            r := B[i] ;
            forever:
                pair q ;
                if how = 1 :
                    r := r cutbefore T[j] ;
                elseif how = 2 :
                    r := r cutbefore reverse T[j] ;
                elseif how = 3 :
                    r := reverse r cutbefore T[j] ;
                else :
                    r := reverse r cutbefore reverse T[j] ;
                fi ;
                exitif length cuttings = 0 ;
                r := subpath(epsilon, length r) of r ;
                q = point 0 of r ;
                isnew := true ;
                rq := round(q);
                for f=1 upto n :
                    if found[f] = rq :
                        isnew := false ;
                        exitif true ;
                    fi ;
                endfor ;
                if isnew :
                    n := n + 1 ;
                    drawdot q withpen pencircle scaled 4 ;
                    draw textext("\strut\ttbf " & decimal n) ysized 3
shifted q withcolor white ;
                    found[n] := rq ;
                fi ;
            endfor;
        endfor ;
    endfor ;
enddef ;

for i=1 upto 4 : GoForIt(i) ; endfor ;

\stopMPpage

\stoptext
Ok, a different approach then (probably still not all points as we need
to loop over segments but better) .. no more time now.

It also shows that we don't need lua/tex juggling as we already can have
the paths in mp. (For sure now someone can complain that this is not
well documented.)

\starttext

\startMPdefinitions

      % will be added to metafun:

      def filloutlinetext(expr o) =
          draw image (
              save n, m ; numeric n, m ; n := m := 0 ;
              for i within o :
                  n := n + 1 ;
              endfor ;
              for i within o :
                  m := m + 1 ;
                  if n = m :
                      eofill
                  else :
                      nofill
                  fi pathpart i ;
              endfor ;
          )
      enddef ;

      def drawoutlinetext(expr o) =
          draw image (
              % nicer for properties
              for i within o :
                  draw pathpart i ;
              endfor ;
          )
      enddef ;

      def outlinetexttopath(text o, p, n) =
          scantokens("numeric " & str n &   ";") ;
          scantokens("path "    & str p & "[];") ;
          n := 0 ;
          for i within o : p[incr(n)] := pathpart i ; endfor ;
      enddef ;

\stopMPdefinitions

\startMPdefinitions

      % outlinetexttopath(Bo)(B)(Bn) ;
      %
      % Bn := listsize(T)

      def showoverlapinoutlines(expr first, second) =

          path p_i, p_j, s_i, s_j ;
          numeric n_i, n_j, index ;
          pair found ;
          index := 0 ;
          for i within first :
              for j within second :
                  p_i := pathpart i ; n_i := length(p_i) ;
                  p_j := pathpart j ; n_j := length(p_j) ;
                  for ii = 0 upto n_i - 1 :
                      s_i := subpath(ii,ii+1) of p_i ;
                      for jj = 0 upto n_j - 1 :
                          s_j := subpath(jj,jj+1) of p_j ;
                          found := s_i intersection_point s_j ;
                          if intersection_found :
                              index := index + 1 ;
                              drawdot found withpen pencircle scaled 4
withtransparency (1,.5);
                              draw textext("\strut\ttbf " & decimal
index) ysized 3 shifted found withcolor white withtransparency (1,.5);
                          fi ;
                      endfor ;
                  endfor ;
              endfor ;
          endfor ;

      enddef ;

\stopMPdefinitions

\startMPpage

      picture first  ; first  := outlinetext.p("N") ; first  := first
scaled 10 ;
      picture second ; second := outlinetext.p("T") ; second := second
scaled 10 ;

      second := second rotatedaround(center second, 5) shifted (1,-1) ;

      filloutlinetext(first ) withcolor .5[blue,white] ;
      filloutlinetext(second) withcolor .5[red,white] ;

      drawoutlinetext(first ) ;
      drawoutlinetext(second) ;

      showoverlapinoutlines(first, second) ;

\stopMPpage

\startMPdefinitions

      def showoverlap(expr f, s) =
          picture first  ; first  := outlinetext.p(f) ; first  := first
scaled 10 ;
          picture second ; second := outlinetext.p(s) ; second := second
scaled 10 ;

          filloutlinetext(first ) withcolor .5blue ;
          drawoutlinetext(first ) ;

          filloutlinetext(second) withcolor .5red  ;
          drawoutlinetext(second) ;

          showoverlapinoutlines(first, second) ;
      enddef ;

\stopMPdefinitions

\startMPpage
      showoverlap("N","T") ;
\stopMPpage

\startMPpage
      showoverlap("\$","Q") ;
\stopMPpage

\startMPpage
      showoverlap("\tttf ABC","\tttf PQR") ;
\stopMPpage

\stoptext


Take a look, also, at the crossingunder macro in mp-tool.mpiv
something

    % based on crossingunder

    def showoverlapinoutlines(expr first, second) =
        begingroup ;
        save p, q, n, t, a, b, c, bcuttings, hold, found ;
        path p, q ;
        numeric n, t[], hold ;
        path a, b, c, bcuttings, hold[] ;
        pair found ;
        c := makepath(currentpen scaled crossingscale) ;
        t[0] := n := hold := 0 ;
        for f within first :
            for s within second :
                p := pathpart f ;
                q := pathpart s ;
                a := p ;
                for i=1 upto crossingnumbermax : % safeguard
                    clearxy ; z = a intersectiontimes q ;
                    if x < 0 :
                        exitif hold < 1 ;
                        a := hold[hold] ; hold := hold - 1 ;
                        clearxy ; z = a intersectiontimes q ;
                    fi
(t[incr n], whatever) = p intersectiontimes point x of a ;
                    if x = 0 :
                        a := a cutbefore c shifted point x of a ;
                    elseif x = length a :
                        a := a cutafter  c shifted point x of a ;
                    else : % before or after?
b := subpath (0,x) of a cutafter c shifted point x of a ;
                        bcuttings := cuttings ;
a := subpath (x,length a) of a cutbefore c shifted point x of a ;
                        clearxy ; z = a intersectiontimes q ;
                        if x < 0 :
                            a := b ;
                            cuttings := bcuttings ;
                        else :
                            if length bcuttings > 0 :
                                clearxy ; z = b intersectiontimes q ;
                                if x >= 0 :
                                    hold[incr hold] := b ;
                                fi
                            fi
                        fi
                    fi
                    if length cuttings = 0 :
                        exitif hold < 1 ;
                        a := hold[hold] ; hold := hold - 1 ;
                    fi
                endfor ;

            endfor ;
        endfor ;

        t[incr n] = length p ;
        for i=1 upto n :
            found := point t[i] of p ;
drawdot found withpen pencircle scaled 4 withtransparency (1,.5); draw textext("\strut\ttbf " & decimal i) ysized 3 shifted found withcolor white withtransparency (1,.5);
        endfor ;

        endgroup ;
    enddef ;



-----------------------------------------------------------------
                                          Hans Hagen | PRAGMA ADE
              Ridderstraat 27 | 8061 GH Hasselt | The Netherlands
       tel: 038 477 53 69 | www.pragma-ade.nl | www.pragma-pod.nl
-----------------------------------------------------------------
___________________________________________________________________________________
If your question is of interest to others as well, please add an entry to the 
Wiki!

maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
webpage  : http://www.pragma-ade.nl / http://context.aanhet.net
archive  : https://bitbucket.org/phg/context-mirror/commits/
wiki     : http://contextgarden.net
___________________________________________________________________________________

Reply via email to