<commit_before># Created: 06.2020
# Copyright (c) 2020, <NAME>
# License: MIT License
import enum
import re
from math import radians
from typing import Union, Tuple, Dict, Iterable, List, Optional, Callable

from ezdxf.entities.text import plain_text

import ezdxf.lldxf.const as DXFConstants
from ezdxf.addons.drawing.backend import Backend
from ezdxf.addons.drawing.debug_utils import draw_rect
from ezdxf.addons.drawing import fonts
from ezdxf.entities import MText, Text, Attrib, AttDef
from ezdxf.math import Matrix44, Vec3, sign

"""
Search google for 'typography' or 'font anatomy' for explanations of terms like 'baseline' and 'x-height'

A Visual Guide to the Anatomy of Typography: https://visme.co/blog/type-anatomy/
Anatomy of a Character: https://www.fonts.com/content/learning/fontology/level-1/type-anatomy/anatomy
"""


@enum.unique
class HAlignment(enum.Enum):
    LEFT = 0
    CENTER = 1
    RIGHT = 2


@enum.unique
class VAlignment(enum.Enum):
    TOP = 0  # the top of capital letters or letters with ascenders (like 'b')
    LOWER_CASE_CENTER = 1  # the midpoint between the baseline and the x-height
    BASELINE = 2  # the line which text rests on, characters with descenders (like 'p') are partially below this line
    BOTTOM = 3  # the lowest point on a character with a descender (like 'p')


Alignment = Tuple[HAlignment, VAlignment]
AnyText = Union[Text, MText, Attrib, AttDef]

# multiple of cap_height between the baseline of the previous line and the baseline of the next line
DEFAULT_LINE_SPACING = 5 / 3

DXF_MTEXT_ALIGNMENT_TO_ALIGNMENT: Dict[int, Alignment] = {
    DXFConstants.MTEXT_TOP_LEFT: (HAlignment.LEFT, VAlignment.TOP),
    DXFConstants.MTEXT_TOP_CENTER: (HAlignment.CENTER, VAlignment.TOP),
    DXFConstants.MTEXT_TOP_RIGHT: (HAlignment.RIGHT, VAlignment.TOP),
    DXFConstants.MTEXT_MIDDLE_LEFT: (HAlignment.LEFT, VAlignment.LOWER_CASE_CENTER),
    DXFConstants.MTEXT_MIDDLE_CENTER: (HAlignment.CENTER, VAlignment.LOWER_CASE_CENTER),
    DXFConstants.MTEXT_MIDDLE_RIGHT: (HAlignment.RIGHT, VAlignment.LOWER_CASE_CENTER),
    DXFConstants.MTEXT_BOTTOM_LEFT: (HAlignment.LEFT, VAlignment.BOTTOM),
    DXFConstants.MTEXT_BOTTOM_CENTER: (HAlignment.CENTER, VAlignment.BOTTOM),
    DXFConstants.MTEXT_BOTTOM_RIGHT: (HAlignment.RIGHT, VAlignment.BOTTOM)
}
assert len(DXF_MTEXT_ALIGNMENT_TO_ALIGNMENT) == len(DXFConstants.MTEXT_ALIGN_FLAGS)


class FontMeasurements:
    def __init__(self, baseline: float, cap_height: float, x_height: float, descender_height: float):
        self.baseline = baseline
        self.cap_height = cap_height
        self.x_height = x_height
        self.descender_height = descender_height

    def __eq__(self, other):
        return (isinstance(other, FontMeasurements) and
                self.baseline == other.baseline and
                self.cap_height == other.cap_height and
                self.x_height == other.x_height and
                self.descender_height == other.descender_height)

    def scale_from_baseline(self, desired_cap_height: float) -> "FontMeasurements":
        scale = desired_cap_height / self.cap_height
        return FontMeasurements(
            baseline=self.baseline,
            cap_height=desired_cap_height,
            x_height=self.x_height * scale,
            descender_height=self.descender_height * scale,
        )

    @property
    def cap_top(self) -> float:
        return self.baseline + self.cap_height

    @property
    def x_top(self) -> float:
        return self.baseline + self.x_height

    @property
    def bottom(self) -> float:
        return self.baseline - self.descender_height


def _get_rotation(text: AnyText) -> Matrix44:
    if isinstance(text, Text):
        return Matrix44.axis_rotate(Vec3(text.dxf.extrusion).normalize(), radians(text.dxf.rotation))
    if isinstance(text, MText):
        return Matrix44.axis_rotate(Vec3(text.dxf.extrusion).normalize(), radians(text.get_rotation()))
    elif isinstance(text, (Attrib, AttDef)):<commit_msg>removed normalisation since #279 was fixed<commit_after># Created: 06.2020
# Copyright (c) 2020, <NAME>
# License: MIT License
import enum
import re
from math import radians
from typing import Union, Tuple, Dict, Iterable, List, Optional, Callable

from ezdxf.entities.text import plain_text

import ezdxf.lldxf.const as DXFConstants
from ezdxf.addons.drawing.backend import Backend
from ezdxf.addons.drawing.debug_utils import draw_rect
from ezdxf.addons.drawing import fonts
from ezdxf.entities import MText, Text, Attrib, AttDef
from ezdxf.math import Matrix44, Vec3, sign

"""
Search google for 'typography' or 'font anatomy' for explanations of terms like 'baseline' and 'x-height'

A Visual Guide to the Anatomy of Typography: https://visme.co/blog/type-anatomy/
Anatomy of a Character: https://www.fonts.com/content/learning/fontology/level-1/type-anatomy/anatomy
"""


@enum.unique
class HAlignment(enum.Enum):
    LEFT = 0
    CENTER = 1
    RIGHT = 2


@enum.unique
class VAlignment(enum.Enum):
    TOP = 0  # the top of capital letters or letters with ascenders (like 'b')
    LOWER_CASE_CENTER = 1  # the midpoint between the baseline and the x-height
    BASELINE = 2  # the line which text rests on, characters with descenders (like 'p') are partially below this line
    BOTTOM = 3  # the lowest point on a character with a descender (like 'p')


Alignment = Tuple[HAlignment, VAlignment]
AnyText = Union[Text, MText, Attrib, AttDef]

# multiple of cap_height between the baseline of the previous line and the baseline of the next line
DEFAULT_LINE_SPACING = 5 / 3

DXF_MTEXT_ALIGNMENT_TO_ALIGNMENT: Dict[int, Alignment] = {
    DXFConstants.MTEXT_TOP_LEFT: (HAlignment.LEFT, VAlignment.TOP),
    DXFConstants.MTEXT_TOP_CENTER: (HAlignment.CENTER, VAlignment.TOP),
    DXFConstants.MTEXT_TOP_RIGHT: (HAlignment.RIGHT, VAlignment.TOP),
    DXFConstants.MTEXT_MIDDLE_LEFT: (HAlignment.LEFT, VAlignment.LOWER_CASE_CENTER),
    DXFConstants.MTEXT_MIDDLE_CENTER: (HAlignment.CENTER, VAlignment.LOWER_CASE_CENTER),
    DXFConstants.MTEXT_MIDDLE_RIGHT: (HAlignment.RIGHT, VAlignment.LOWER_CASE_CENTER),
    DXFConstants.MTEXT_BOTTOM_LEFT: (HAlignment.LEFT, VAlignment.BOTTOM),
    DXFConstants.MTEXT_BOTTOM_CENTER: (HAlignment.CENTER, VAlignment.BOTTOM),
    DXFConstants.MTEXT_BOTTOM_RIGHT: (HAlignment.RIGHT, VAlignment.BOTTOM)
}
assert len(DXF_MTEXT_ALIGNMENT_TO_ALIGNMENT) == len(DXFConstants.MTEXT_ALIGN_FLAGS)


class FontMeasurements:
    def __init__(self, baseline: float, cap_height: float, x_height: float, descender_height: float):
        self.baseline = baseline
        self.cap_height = cap_height
        self.x_height = x_height
        self.descender_height = descender_height

    def __eq__(self, other):
        return (isinstance(other, FontMeasurements) and
                self.baseline == other.baseline and
                self.cap_height == other.cap_height and
                self.x_height == other.x_height and
                self.descender_height == other.descender_height)

    def scale_from_baseline(self, desired_cap_height: float) -> "FontMeasurements":
        scale = desired_cap_height / self.cap_height
        return FontMeasurements(
            baseline=self.baseline,
            cap_height=desired_cap_height,
            x_height=self.x_height * scale,
            descender_height=self.descender_height * scale,
        )

    @property
    def cap_top(self) -> float:
        return self.baseline + self.cap_height

    @property
    def x_top(self) -> float:
        return self.baseline + self.x_height

    @property
    def bottom(self) -> float:
        return self.baseline - self.descender_height


def _get_rotation(text: AnyText) -> Matrix44:
    if isinstance(text, Text):
        return Matrix44.axis_rotate(text.dxf.extrusion, radians(text.dxf.rotation))
    if isinstance(text, MText):
        return Matrix44.axis_rotate(text.dxf.extrusion, radians(text.get_rotation()))
    elif isinstance(text, (Attrib, AttDef)):
{'fraction_non_alphanumeric': 0.0898383661195339, 'fraction_numerical': 0.007893747650670342, 'mean_word_length': 3.8670731707317074, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 15, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6416905', 'n_tokens_mistral': 2654, 'n_tokens_neox': 2542, 'n_words': 628}