Итак понадобилось мне написать редактор формул, наподобие MathType, но с той лишь разницей, что формулы он должен был строить по некоторому коду, к примеру:
- Код: Выделить всё
b-\drb{b}{x}
Т.е от b отнять дробь
- Код: Выделить всё
b/x
сразу же оговорюсь, что верстальщики формул наподобие Latex мне не подходят (во первых это слишком мощно для моей маленькой программы, во вторых время компиляции латех документа очень долго, в третьих формула должна быть легко компилируема в рисунок jpg)
Результатом моего желания явилась эта программа (написана целиком на Vb6, проект прилагаю).
По сути это написанный мной некогда редактор карт для простых игрушек с использованием StretchBlt, но переделанный под отбражение формул.
Не буду описывать весь код, суть в том, что элементы формул, такие как x,y,z,+ запихнуты в коллекцию текстур брашей, браши добавляются в определенное место на форме (документе).
Суть программы в том, чтобы найти позицию для каждого браша (поставить знак в нужное место на форме).
За это отвечает в программе следующая функция:
- Код: Выделить всё
Private Function CalcFormula(fstring As String, nx As Single, ny As Single, sizeum As Variant, ex As Boolean) As PicTexSize
Dim i As Integer
Dim res As Boolean
Dim sm As String
Dim fsize As PicTexSize
Dim perpr As String
Dim vtpr As String
Dim xs1 As Integer
Dim xs2 As Integer
i = 0
dist = 3
allsizeH = 0
begx = nx
If fstring = "" Then CalcFormula.height = 0: CalcFormula.width = 0: Exit Function
Do
i = i + 1
sm = Mid(fstring, i, 1)
'Добавление односимовольного браша-формулы
If SetTexFor(sm) Then
plussizeH = GetPixSize(nowPix).height
If allsizeH = 0 Then allsizeH = plussizeH
If ex = True Then addBrush nx, ny - GetPixSize(nowPix).height / 2, sizeum, sizeum
nx = nx + GetPixSize(nowPix).width + dist * sizeum * sizeum
End If
'Добавление многосимвольного браша формулы
If sm = "\" Then
xs = InStr(i, fstring, " ")
If xs <> 0 Then
sm = Mid(fstring, i + 1, xs - i - 1)
i = xs
If SetTexFor(sm) Then
plussizeH = GetPixSize(nowPix).height
If allsizeH = 0 Then allsizeH = plussizeH
If ex = True Then addBrush nx, ny - GetPixSize(nowPix).height / 2, sizeum, sizeum
nx = nx + GetPixSize(nowPix).width * sizeum + dist * sizeum
End If
End If
End If
'Добавление сложного браша формулы
If sm = "\" Then
xs1 = 0
xk1 = 0
xs2 = 0
xk2 = 0
xs1 = InStr(i, fstring, "{")
If xs1 <> 0 Then sm = Mid(fstring, i + 1, xs1 - i - 1) Else sm = ""
If xs1 = 0 Then
xk1 = 0
xs2 = 0
perpr = ""
Else
xk1 = GetLastStr(xs1, fstring, "}", "{")
If xk1 = 0 Then perpr = "" Else perpr = Mid(fstring, xs1 + 1, xk1 - xs1 - 1): i = xk1
End If
If xk1 <> 0 Then xs2 = InStr(xk1, fstring, "{")
If xs2 = 0 Then
vtpr = ""
xk2 = 0
Else
xk2 = GetLastStr(xs2, fstring, "}", "{")
If xk2 = 0 Then vtpr = "" Else vtpr = Mid(fstring, xs2 + 1, xk2 - xs2 - 1): i = xk2
End If
If (perpr <> "" And sm <> "") Then
fsize = AddSlFunc(sm, perpr, vtpr, nx, ny, sizeum, ex)
nx = nx + fsize.width + dist * sizeum
plussizeH = fsize.height
End If
End If
If plussizeH > allsizeH Then allsizeH = plussizeH
If i = Len(fstring) Then CalcFormula.height = allsizeH: CalcFormula.width = nx - begx: nx = begx: Exit Function
Loop
End Function
Может быть все довольно сложновато, но на первый взгляд:
взглянем внимательней:
nx - начало текущего фрагмента формулы по оси x
ny - средняя линия (т.е. горизонтальная линия проходящая через середину текущего фрагмента формулы)
fstring - код формулы
sizeum - коофициент уменьшения размера фрагмента формулы, 1 без уменьшения
ex - указатель отображать ли элементы формулы или лишь расчитывать размер фрагмента.
Итак данная функция расчитывает размер фрагмента формулы и отображает элементы (браши) на средней линии (или не отображает).
Для того, чтобы отображать сложные элементы (такие как дробь или степень) существует отдельная функция:
- Код: Выделить всё
Private Function AddSlFunc(tfor As String, par1 As String, par2 As String, nx As Single, ny As Single, sizeum As Variant, ex As Boolean) As PicTexSize
Dim fsize As PicTexSize
Dim f2size As PicTexSize
Dim tpar1 As String
Dim tpar2 As String
'Добавление сложных брашей
Select Case tfor
Case "drb"
'Добавление дроби
tpar1 = par1
tpar2 = par2
'Предрасчет размеров числителей и знаменателей
fsize = CalcFormula(tpar1, nx, ny, sizeum, False)
f2size = CalcFormula(tpar2, nx, ny, sizeum, False)
'Добавление числителя и знаменателя.
fsize = CalcFormula(tpar1, nx, ny - (fsize.height) / 2 - 3, sizeum, ex)
f2size = CalcFormula(tpar2, nx, ny + (f2size.height) / 2 + 3, sizeum, ex)
SetTexFor ("-")
If f2size.width >= fsize.width Then AddSlFunc.width = f2size.width Else AddSlFunc.width = fsize.width
addBrush nx, ny, (AddSlFunc.width / GetPixSize(nowPix).width), 1
AddSlFunc.height = fsize.height + f2size.height + 4
AddSlFunc.width = AddSlFunc.width
Case "dg"
'Добавление степени'
fsize = CalcFormula(par1, nx, ny, sizeum, False)
fsize = CalcFormula(par1, nx, ny, sizeum, ex)
f2size = CalcFormula(par2, nx, ny, sizeum * 0.8, False)
f2size = CalcFormula(par2, nx + fsize.width, ny - fsize.height / 2, sizeum * 0.8, ex)
AddSlFunc.width = (fsize.width + f2size.width)
AddSlFunc.height = fsize.height + f2size.height
End Select
End Function
Обе данные функции возвращают размеры формул в типе Pictexsize.
Последняя функция имеет параметрами:
tfor - название слож функции (если дробь то drb)
par1, par2 - в дроби числитель и знаменатель (фрагменты формулы)
ну и те же параметры, что в первой функции.
Суть работы второй функции в следующем - расчитать размер числителя и знаменателя рекурсивно запустив опять CalcFormula, но уже для фрагментов числителя и знаменателя. Получив размеры фрагментов формул числителя и знаменателя запускаем CalcFormula для обоих и рендерим числитель над средней линией а знаменатель под средней линией и на средней линии ренедерим прямую. Получаем красивую такую дробь. Попытался объяснить как мог.
Итак внимание, вопрос: все прекрасно работает, НО введите формулу:
\drb{x\drb{x}{b}}{b}. Во второй дроби (внутренней) b залез под черту первой. Почему? Сижу над этим вопросом уже неделю.
Все функции описанные выше, а также ряд вспомогательных находятся в модуле формы: frmOptions
[/code]