Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
M
Molstar
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Michal Malý
Molstar
Commits
a11c447e
Commit
a11c447e
authored
6 years ago
by
Alexander Rose
Browse files
Options
Downloads
Patches
Plain Diff
wip, text-atlas for edt text rendering
parent
01e0ae4e
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
src/mol-geo/geometry/text/text-atlas.ts
+196
-0
196 additions, 0 deletions
src/mol-geo/geometry/text/text-atlas.ts
src/mol-math/geometry/distance-transform.ts
+55
-0
55 additions, 0 deletions
src/mol-math/geometry/distance-transform.ts
with
251 additions
and
0 deletions
src/mol-geo/geometry/text/text-atlas.ts
0 → 100644
+
196
−
0
View file @
a11c447e
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import
{
ParamDefinition
as
PD
}
from
'
mol-util/param-definition
'
;
import
{
edt
}
from
'
mol-math/geometry/distance-transform
'
;
const
TextAtlasCache
:
{
[
k
:
string
]:
TextAtlas
}
=
{}
export
function
getTextAtlas
(
props
:
Partial
<
TextAtlasProps
>
)
{
const
hash
=
JSON
.
stringify
(
props
)
if
(
TextAtlasCache
[
hash
]
===
undefined
)
{
TextAtlasCache
[
hash
]
=
new
TextAtlas
(
props
)
}
return
TextAtlasCache
[
hash
]
}
export
type
TextFonts
=
'
sans-serif
'
|
'
monospace
'
|
'
serif
'
|
'
cursive
'
export
type
TextStyles
=
'
normal
'
|
'
italic
'
|
'
oblique
'
export
type
TextVariants
=
'
normal
'
|
'
small-caps
'
export
type
TextWeights
=
'
normal
'
|
'
bold
'
export
const
TextAtlasParams
=
{
fontFamily
:
PD
.
Select
(
'
sans-serif
'
,
[[
'
sans-serif
'
,
'
Sans Serif
'
],
[
'
monospace
'
,
'
Monospace
'
],
[
'
serif
'
,
'
Serif
'
],
[
'
cursive
'
,
'
Cursive
'
]]
as
[
TextFonts
,
string
][]),
fontSize
:
PD
.
Numeric
(
36
,
{
min
:
4
,
max
:
96
,
step
:
1
}),
fontStyle
:
PD
.
Select
(
'
normal
'
,
[[
'
normal
'
,
'
Normal
'
],
[
'
italic
'
,
'
Italic
'
],
[
'
oblique
'
,
'
Oblique
'
]]
as
[
TextStyles
,
string
][]),
fontVariant
:
PD
.
Select
(
'
normal
'
,
[[
'
normal
'
,
'
Normal
'
],
[
'
small-caps
'
,
'
Small Caps
'
]]
as
[
TextVariants
,
string
][]),
fontWeight
:
PD
.
Select
(
'
normal
'
,
[[
'
normal
'
,
'
Normal
'
],
[
'
bold
'
,
'
Bold
'
]]
as
[
TextWeights
,
string
][]),
width
:
PD
.
Numeric
(
1024
),
height
:
PD
.
Numeric
(
1024
)
}
export
type
TextAtlasParams
=
typeof
TextAtlasParams
export
type
TextAtlasProps
=
PD
.
Values
<
TextAtlasParams
>
export
type
TextAtlasMap
=
{
x
:
number
,
y
:
number
,
w
:
number
,
h
:
number
}
export
class
TextAtlas
{
readonly
props
:
Readonly
<
TextAtlasProps
>
readonly
mapped
:
{
[
k
:
string
]:
TextAtlasMap
}
=
{}
readonly
placeholder
:
TextAtlasMap
readonly
context
:
CanvasRenderingContext2D
private
canvas
:
HTMLCanvasElement
private
scratchW
=
0
private
scratchH
=
0
private
currentX
=
0
private
currentY
=
0
private
readonly
cutoff
=
0.25
private
padding
:
number
private
radius
:
number
private
gridOuter
:
Float64Array
private
gridInner
:
Float64Array
private
f
:
Float64Array
private
d
:
Float64Array
private
z
:
Float64Array
private
v
:
Int16Array
private
scratchCanvas
:
HTMLCanvasElement
private
scratchContext
:
CanvasRenderingContext2D
private
lineHeight
:
number
private
maxWidth
:
number
private
middle
:
number
constructor
(
props
:
Partial
<
TextAtlasProps
>
=
{})
{
const
p
=
{
...
PD
.
getDefaultValues
(
TextAtlasParams
),
...
props
}
this
.
props
=
p
this
.
padding
=
p
.
fontSize
/
8
this
.
radius
=
p
.
fontSize
/
3
this
.
lineHeight
=
Math
.
round
(
p
.
fontSize
+
6
*
this
.
padding
)
this
.
maxWidth
=
this
.
lineHeight
*
1.5
// Prepare scratch canvas
this
.
scratchCanvas
=
document
.
createElement
(
'
canvas
'
)
this
.
scratchCanvas
.
width
=
this
.
maxWidth
this
.
scratchCanvas
.
height
=
this
.
lineHeight
this
.
scratchContext
=
this
.
scratchCanvas
.
getContext
(
'
2d
'
)
!
this
.
scratchContext
.
font
=
`
${
p
.
fontStyle
}
${
p
.
fontVariant
}
${
p
.
fontWeight
}
${
p
.
fontSize
}
px
${
p
.
fontFamily
}
`
this
.
scratchContext
.
fillStyle
=
'
black
'
this
.
scratchContext
.
textBaseline
=
'
middle
'
// temporary arrays for the distance transform
this
.
gridOuter
=
new
Float64Array
(
this
.
lineHeight
*
this
.
maxWidth
)
this
.
gridInner
=
new
Float64Array
(
this
.
lineHeight
*
this
.
maxWidth
)
this
.
f
=
new
Float64Array
(
Math
.
max
(
this
.
lineHeight
,
this
.
maxWidth
))
this
.
d
=
new
Float64Array
(
Math
.
max
(
this
.
lineHeight
,
this
.
maxWidth
))
this
.
z
=
new
Float64Array
(
Math
.
max
(
this
.
lineHeight
,
this
.
maxWidth
)
+
1
)
this
.
v
=
new
Int16Array
(
Math
.
max
(
this
.
lineHeight
,
this
.
maxWidth
))
this
.
middle
=
Math
.
ceil
(
this
.
lineHeight
/
2
)
//
this
.
canvas
=
document
.
createElement
(
'
canvas
'
)
this
.
canvas
.
width
=
p
.
width
this
.
canvas
.
height
=
p
.
height
this
.
context
=
this
.
canvas
.
getContext
(
'
2d
'
)
!
// Replacement Character
this
.
placeholder
=
this
.
map
(
String
.
fromCharCode
(
0xFFFD
))
// Basic Latin (subset)
for
(
let
i
=
0x0020
;
i
<=
0x007E
;
++
i
)
this
.
map
(
String
.
fromCharCode
(
i
))
// TODO: to slow to always prepare them
// // Latin-1 Supplement (subset)
// for (let i = 0x00A1; i <= 0x00FF; ++i) this.map(String.fromCharCode(i))
// Degree sign
this
.
map
(
String
.
fromCharCode
(
0x00B0
))
// // Greek and Coptic (subset)
// for (let i = 0x0391; i <= 0x03C9; ++i) this.map(String.fromCharCode(i))
// // Cyrillic (subset)
// for (let i = 0x0400; i <= 0x044F; ++i) this.map(String.fromCharCode(i))
// Angstrom Sign
this
.
map
(
String
.
fromCharCode
(
0x212B
))
}
map
(
text
:
string
)
{
if
(
this
.
mapped
[
text
]
===
undefined
)
{
this
.
draw
(
text
)
if
(
this
.
currentX
+
this
.
scratchW
>
this
.
props
.
width
)
{
this
.
currentX
=
0
this
.
currentY
+=
this
.
scratchH
}
if
(
this
.
currentY
+
this
.
scratchH
>
this
.
props
.
height
)
{
console
.
warn
(
'
canvas to small
'
)
}
this
.
mapped
[
text
]
=
{
x
:
this
.
currentX
,
y
:
this
.
currentY
,
w
:
this
.
scratchW
,
h
:
this
.
scratchH
}
this
.
context
.
drawImage
(
this
.
scratchCanvas
,
0
,
0
,
this
.
scratchW
,
this
.
scratchH
,
this
.
currentX
,
this
.
currentY
,
this
.
scratchW
,
this
.
scratchH
)
this
.
currentX
+=
this
.
scratchW
}
return
this
.
mapped
[
text
]
}
get
(
text
:
string
)
{
return
this
.
mapped
[
text
]
||
this
.
placeholder
}
draw
(
text
:
string
)
{
const
h
=
this
.
lineHeight
const
ctx
=
this
.
scratchContext
// Measure text
const
m
=
ctx
.
measureText
(
text
)
const
w
=
Math
.
min
(
this
.
maxWidth
,
Math
.
ceil
(
m
.
width
+
2
*
this
.
padding
+
this
.
radius
/
2
))
const
n
=
w
*
h
ctx
.
clearRect
(
0
,
0
,
w
,
h
)
// clear scratch area
ctx
.
fillText
(
text
,
this
.
padding
+
this
.
radius
/
4
,
this
.
middle
)
// draw text
const
imageData
=
ctx
.
getImageData
(
0
,
0
,
w
,
h
)
const
data
=
imageData
.
data
for
(
let
i
=
0
;
i
<
n
;
i
++
)
{
const
a
=
imageData
.
data
[
i
*
4
+
3
]
/
255
// alpha value
this
.
gridOuter
[
i
]
=
a
===
1
?
0
:
a
===
0
?
Number
.
MAX_SAFE_INTEGER
:
Math
.
pow
(
Math
.
max
(
0
,
0.5
-
a
),
2
)
this
.
gridInner
[
i
]
=
a
===
1
?
Number
.
MAX_SAFE_INTEGER
:
a
===
0
?
0
:
Math
.
pow
(
Math
.
max
(
0
,
a
-
0.5
),
2
)
}
edt
(
this
.
gridOuter
,
w
,
h
,
this
.
f
,
this
.
d
,
this
.
v
,
this
.
z
)
edt
(
this
.
gridInner
,
w
,
h
,
this
.
f
,
this
.
d
,
this
.
v
,
this
.
z
)
for
(
let
i
=
0
;
i
<
n
;
i
++
)
{
const
d
=
this
.
gridOuter
[
i
]
-
this
.
gridInner
[
i
];
data
[
i
*
4
+
3
]
=
Math
.
max
(
0
,
Math
.
min
(
255
,
Math
.
round
(
255
-
255
*
(
d
/
this
.
radius
+
this
.
cutoff
))));
}
ctx
.
putImageData
(
imageData
,
0
,
0
)
this
.
scratchW
=
w
this
.
scratchH
=
h
}
}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
src/mol-math/geometry/distance-transform.ts
0 → 100644
+
55
−
0
View file @
a11c447e
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
/**
* 2D Euclidean distance transform by Felzenszwalb & Huttenlocher https://cs.brown.edu/~pff/papers/dt-final.pdf
*/
export
function
edt
(
data
:
Helpers
.
NumberArray
,
width
:
number
,
height
:
number
,
f
:
Helpers
.
NumberArray
,
d
:
Helpers
.
NumberArray
,
v
:
Helpers
.
NumberArray
,
z
:
Helpers
.
NumberArray
)
{
for
(
let
x
=
0
;
x
<
width
;
x
++
)
{
for
(
let
y
=
0
;
y
<
height
;
y
++
)
{
f
[
y
]
=
data
[
y
*
width
+
x
]
}
edt1d
(
f
,
d
,
v
,
z
,
height
)
for
(
let
y
=
0
;
y
<
height
;
y
++
)
{
data
[
y
*
width
+
x
]
=
d
[
y
]
}
}
for
(
let
y
=
0
;
y
<
height
;
y
++
)
{
for
(
let
x
=
0
;
x
<
width
;
x
++
)
{
f
[
x
]
=
data
[
y
*
width
+
x
]
}
edt1d
(
f
,
d
,
v
,
z
,
width
)
for
(
let
x
=
0
;
x
<
width
;
x
++
)
{
data
[
y
*
width
+
x
]
=
Math
.
sqrt
(
d
[
x
])
}
}
}
/**
* 1D squared distance transform
*/
function
edt1d
(
f
:
Helpers
.
NumberArray
,
d
:
Helpers
.
NumberArray
,
v
:
Helpers
.
NumberArray
,
z
:
Helpers
.
NumberArray
,
n
:
number
)
{
v
[
0
]
=
0
z
[
0
]
=
Number
.
MIN_SAFE_INTEGER
z
[
1
]
=
Number
.
MAX_SAFE_INTEGER
for
(
let
q
=
1
,
k
=
0
;
q
<
n
;
q
++
)
{
let
s
=
((
f
[
q
]
+
q
*
q
)
-
(
f
[
v
[
k
]]
+
v
[
k
]
*
v
[
k
]))
/
(
2
*
q
-
2
*
v
[
k
])
while
(
s
<=
z
[
k
])
{
k
--
s
=
((
f
[
q
]
+
q
*
q
)
-
(
f
[
v
[
k
]]
+
v
[
k
]
*
v
[
k
]))
/
(
2
*
q
-
2
*
v
[
k
])
}
k
++
v
[
k
]
=
q
z
[
k
]
=
s
z
[
k
+
1
]
=
Number
.
MAX_SAFE_INTEGER
}
for
(
let
q
=
0
,
k
=
0
;
q
<
n
;
q
++
)
{
while
(
z
[
k
+
1
]
<
q
)
k
++
d
[
q
]
=
(
q
-
v
[
k
])
*
(
q
-
v
[
k
])
+
f
[
v
[
k
]]
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment