daqana / tikzDevice

A R package for producing graphics output as PGF/TikZ code for use in TeX documents.
https://daqana.github.io/tikzDevice
132 stars 26 forks source link

bad behavior of text function. #157

Closed jszhao closed 7 years ago

jszhao commented 7 years ago

In the following example

library(tikzDevice)
options(tikzDefaultEngine = "xetex")
options(tikzXelatexPackages = c(getOption("tikzXelatexPackages"),
                                "\\setmainfont{Times New Roman}\n",
                                "\\usepackage[math-style=TeX]{unicode-math}\n",
                                "\\setmathfont{Times New Roman}\n",
                                "\\usepackage{xeCJK}\n", 
                                "\\setCJKmainfont{SimHei}\n\n"
                                ))
tikz('a.tex', standAlone = TRUE, width=4, height=4)
plot(0, type = "n", xlab = "", ylab = "", axes = FALSE)
text(5,2, "abcd!")
dev.off()

The output in the R console is:

> text(5,2, "abcd!")
Using TikZ metrics dictionary at:
        C:/Users/LENOVO/Documents/R/tikzMetrics
Measuring dimensions of:  abcd!
Measuring dimensions of: \char97
Measuring dimensions of: \char98
Measuring dimensions of: \char99
Measuring dimensions of: \char100
Measuring dimensions of: \char33
> dev.off()

If I replace the text(..., "abcd!") with mtext("abcd!",...), it just give:

Measuring dimensions of:  abcd!

What is the difference? And, why is the string in text measured character by character, instead of string as a whole?

jszhao commented 7 years ago

When I replace the whole TikZ_MetricInfo fucntion in tikzDevice.c with the following code:

static void TikZ_MetricInfo(int c, const pGEcontext plotParams,
    double *ascent, double *descent, double *width, pDevDesc deviceInfo ){
   *ascent = 0.0;
   *descent = 0.0;
   *width = 0.0;
   return;
}

The following message disappear.

Measuring dimensions of: \char97
Measuring dimensions of: \char98
Measuring dimensions of: \char99
Measuring dimensions of: \char100
Measuring dimensions of: \char33

And I also get the correct result.

And again, the https://github.com/yihui/tikzDevice/issues/155 could give correct output and don't hang again.

I think the measurement of character metrics is not necessary when using tikzDevice, since TikZ_StrWidth call R function getLatexStrWidth, which call getLatexCharMetrics, and both of them are the returns calculated by LaTeX.

jszhao commented 7 years ago

well, set all ascent, descent, and width to zero is not a good solution to https://github.com/yihui/tikzDevice/issues/155, however, TikZ_MetricInfo can not provide a good solution. For example, in the following code:

text(0,1,"\\TeX")

It's nonsense to give ascent and descent of e, since in the final typeset, it is an E with shift in vertical direction.

I think it's better to use the ascent, descent, and width of the whole string, if possible.

In the R function getMetricsFromLatex, there is

  # We calculate width for both characters and strings.
  writeLines("\\path let \\p1 = ($(TeX.east) - (TeX.west)$),
    \\n1 = {veclen(\\x1,\\y1)} in (TeX.east) -- (TeX.west)
    node{ \\typeout{tikzTeXWidth=\\n1} };", texIn)

  # We only want ascent and descent for characters.
  if( TeXMetrics$type == 'char' ){

    # Calculate the ascent and print it to the log.
    writeLines("\\path let \\p1 = ($(TeX.north) - (TeX.base)$),
      \\n1 = {veclen(\\x1,\\y1)} in (TeX.north) -- (TeX.base)
      node{ \\typeout{tikzTeXAscent=\\n1} };", texIn)

    # Calculate the descent and print it to the log.
    writeLines("\\path let \\p1 = ($(TeX.base) - (TeX.south)$),
      \\n1 = {veclen(\\x1,\\y1)} in (TeX.base) -- (TeX.south)
      node{ \\typeout{tikzTeXDescent=\\n1} };", texIn)

  }

if we remove the condition to char, then the function can return ascent, descent, and width for both string and character. It doesn't cost additional time.

Now, the problem is how to assign the ascent, descent, and width of whole string to MetricInfo in the C code.

krlmlr commented 7 years ago

Graphics devices such as tikzDevice register a set of callbacks, which are then called by R's graphics engine. We don't control which callbacks are called when. I agree that measuring the metrics character by character doesn't make sense for \TeX and LaTeX commands in general, but this needs to be fixed in base R if at all. Maybe the newer grid functions aren't affected by this problem?

Closing in favor of #160.