Задать вопрос
  • Как из SVG сделать шрифт с большим количеством глифов?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Программированием в FontForge на Змее-Питоне.
    file = open('hani-tofu.txt', 'r')
    for line0 in file:
        line = line0.strip()
        if (line != '') and (not line.startswith('#')):
            code = int(line, base=16)
            svgName = "AutoRemade/{}.svg".format(line)
            glyph = font.createChar(code)
            glyph.glyphname = "u" + line.upper()
            glyph.importOutlines(svgName, scale=False)
            glyph.transform(mat)
            glyph.width = 1000
    Ответ написан
    Комментировать
  • Стоит ли использовать типы данных из cstdint?

    @Mercury13
    Программист на «си с крестами» и не только
    Для олимпиадного программирования.
    Если результат до 109 — то int.
    Если до 1018 — то long long!
    Long’ом лучше не пользоваться.
    Можно также использовать int_fast32_t и int_fast64_t.
    Но всё это ТОЛЬКО В СЛУЧАЕ, ЕСЛИ МЫ НЕ ЗАКЛАДЫВАЕМСЯ НА ПЕРЕПОЛНЕНИЕ.
    Если закладываемся — тогда чёткие int32_t и int64_t, без разговоров.
    Ответ написан
    Комментировать
  • Как ограничить скорость разгона?

    @Mercury13
    Программист на «си с крестами» и не только
    Итак, тут у нас задача: каким образом, НАИМЕНЬШЕЙ КРОВЬЮ (игра совершенно условная, верно?) сделать поведение машины в зависимости от оборотов. Опустим сложные материи вроде приёмистости, турбины, торможения двигателем, спойлеров, дифференциала, увода шин и прочего. Считаем, что обороты мотора измеряем в об/мин, остальное (скорости, расстояния…) — в единицах СИ.

    1. Нам нужны передаточные числа коробки в единицах «обороты·c/м·мин». Имея физическую машину в гараже и инструкцию к ней, действуем так: замеряем действующий радиус колеса с учётом смятой шины, находим передаточные числа передач в коробке и главной передачи, и

    об·/метр = (передаточное_число_коробки·передаточное_число_главной_передачи)/(120π·радиус_колеса).

    Ну или просто едем на стабильной скорости, замеряем скорость GPS’ом или километровыми знаками (важно! — спидометр всегда врёт), и заодно видим обороты мотора.

    Если физической нет — находим похожую, узнаём передаточные числа, узнаём, на какой передаче достигается максимальная скорость (часто в народных машинах, не способных ездить за 200, высшая является овердрайвом, служит для экономии топлива и моторесурса, и в экстриме не используется), находим соответствующие обороты мотора, и обороты на скорость — получаем данное число для самой скоростной передачи. Для остальных пропорционально.

    2. Теперь придумываем сопротивление движению в виде квадратного трёхчлена: Fсопр=av²+bv. Цифры a и b находим из двух условий: а) на максимальной скорости Fсопр=Pmax/v; б) линейная часть равна квадратичной где-то около 30 км/ч.

    3. Находим характеристику двигателя: МОЩНОСТЬ от оборотов. Загоняем её в игру в виде ломаной или сплайна.

    4. Прикидываем мощность мотора P в зависимости от положения газа, оборотов и этой кривой.

    5. Ускорение машины: a = (P/v−Fсопр(v))/m, с какой-нибудь аппроксимацией, когда скорость меньше минимальной стабильной (5…10 км/ч в зависимости от машины).

    6. Из скорости через наши «круго-линейные» передаточные числа определяем новые обороты двигателя и ударился ли он в отсечку. Если ударился, ограничиваем скорость.

    7. Если машина вдруг прыгает (хоть одно ведущее колесо в воздухе) — просто считай, что она на нейтрали.

    8. Во время переключения передач ручная машина должна быть на нейтрали, а поскольку игра типа NFS — перехватывай на это время у игрока управление оборотами, чтобы переключение было красивым и без рывков. На автоматической и роботе с двумя сцеплениями какая-то доля мощности приходит на колёса.

    9. На малых скоростях есть ещё один ограничивающий фактор — пробуксовка шин. Если игра условная, то просто коряво рассчитай трение шин и не допускай такого разгона, что шины буксуют.
    Ответ написан
    Комментировать
  • Как понять rvalue ссылки? Когда использовать std::move, а когда std::forward?

    @Mercury13
    Программист на «си с крестами» и не только
    Я их называю «врéменные ссылки» — то есть ссылки на временный безымянный объект, возникший в процессе вычисления значения выражения. Отличается тем, что обычно ссылки на временные объекты принимают заоптимизированные деструктивные функции, которые этот объект готовы выпотрошить в своих целях.

    Функция move предназначена для превращения ссылки (именованной или временной) во временную. Например, чтобы сказать: это именованный объект, но спокойно потрошите его, мне он не нужен.

    У Си++ есть одна фишка:
    void bar(std::string&& x) {}
    
    void foo(std::string&& x) {
      bar(std::move(x));
    }
    
    int main() {
      std::string x = "Test";
      foo (std::move(x));
      return 0;
    }

    То есть снаружи foo требует временную ссылку. Но внутри эта ссылка для ошибкобезопасности обычная именованная! В данном случае, когда функция нешаблонная, мы можем поставить move, но что делать в шаблоне?

    Автоопределение типов тут пасует, потому приходится так.
    template <class T>
    void foo(T&& x) {
      bar(std::forward<T>(x));
    }

    Да, я написал «ошибкобезопасность», хотя функция типа усложняет код. Дело в том, что потеря данных всегда хуже, чем неоптимальный код.

    Таким образом, move — это превращение ссылки (обычной или временной) во временную. Что-то вроде: «Потрошите этот объект спокойно, он мне не нужен».

    Forward — это прикидка, по какой ссылке (обычной или временной) мы передавали объект в функцию, и передача по цепочке таким же образом. Используется только в шаблонах.

    Вот моё описание всего этого.
    https://mercury13-kiev.livejournal.com/96961.html
    Ответ написан
    Комментировать
  • Qt: как сделать, чтобы пункт меню и горячая клавиша делали чуть разное?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Всё оказалось просто. Создаём QAction и QShortcut с одной кнопкой. В ситуации, когда QAction недоступен, QShortcut делаем доступным, и наоборот.
    Ответ написан
    Комментировать
  • Как сделать чтобы программа не запускала процес на каждый аргумент, а запускала один процес на все аргументы?

    @Mercury13
    Программист на «си с крестами» и не только
    Под Windows это делается через DDE.
    Штука сильно устаревшая, однако осталась именно на это — поддержку нескольких файлов через файловый менеджер.
    Ответ написан
    2 комментария
  • Как заменить мышь, и установить чувствительность как было раньше?

    @Mercury13
    Программист на «си с крестами» и не только
    X — это DPI мыши. Я сам чувствителен к этому самому DPI, но я не настолько крутой геймер и мне ±15% вполне покатит.

    Купи геймерскую мышь с плавной установкой DPI и установи такой же, какой был.

    Кроме того, есть ещё один скрытый параметр — качество сенсора. В 2006 было время: покупаешь мышку, а она время от времени устраивает срыв: курсор уходит ХЗ куда. Разумеется, это недопустимо, но умные люди подключили методы решения некорректно поставленных задач, и мыши перестали срываться. Главная фишка этого метода: чем меньше решение по модулю, тем оно предпочтительнее. Это приводит к т.н. отрицательному ускорению мыши: если мышь походит А→Б быстро, курсор пройдёт меньшее расстояние, чем если бы её провели медленно. Если старая (или новая) мышь не очень качественная, отклик будет немножко не такой.
    Ответ написан
    Комментировать
  • Работа с рисованием в Qt. Почему не получается рисовать после оператора if?

    @Mercury13
    Программист на «си с крестами» и не только
    Дело тут вот в чём. События рисования могут проскакивать когда угодно по любому чиху, и потому механизмы перерисовки надо делать такие, что когда угодно этот paintEvent() проскочит — изображение в окне будет корректно восстановлено.

    Например:
    enum class Shape { NONE, LINE, ELLIPSE, RECTANGLE };
    
    ... в форме...
    Shape shareToDraw = Shape::NONE;

    …соответственно в коде нажатия кнопок устанавливаем эту shapeToDraw,
    а paintEvent реагирует на неё.

    У вас же, как только paintEvent() повторно проскочит, ни одно событие не будет отмечено, и он ничего не сделает. А ведь он может дважды проскочить, чтобы нарисовать непрямоугольную область. Или если оконный менеджер что-то попросил.
    Ответ написан
  • Почему поведение fscanf ( stdin, "%c", &c ) различается при чтении EOF в msvc и gcc?

    @Mercury13
    Программист на «си с крестами» и не только
    В таком случае, когда есть подозрение на конец файла, надо проверять возвращаемое значение функции fscanf:
    • EOF — файл закончился;
    • 0 — не прочитали (в данном случае, когда читаем символ такого явно не будет);
    • 1 — прочитали.

    Если во втором случае MSVC возвращает EOF, но заполняет — поведение некузявое, но допустимое.
    Если во втором случае MSVC возвращает 1 — поведение дрянь.

    Вообще для такого дела fscanf — большая пушка, лучше использовать fgetc.
    Ответ написан
  • Чем отличаются любительские МК от промышленных?

    @Mercury13
    Программист на «си с крестами» и не только
    AVR, сердце Arduino, когда-то имел «любительские» и «промышленные» версии. Я уже не помню буквенные индексы.
    Промышленные отличались более высоким диапазоном рабочих температур.
    Сейчас их нет — выход хороших микросхем, видимо, уже достаточно большой. Нет нужды особо продавать «не-совсем-хорошие» микросхемы.
    Ответ написан
    7 комментариев
  • Чужой шрифт в рекламном видео. Добросовестка или нет?

    @Mercury13
    Программист на «си с крестами» и не только
    Если это материал от рекламодателя, который ты вставил с разрешения рекламодателя без изменений — пусть рекламодатель и отвечает, из чего он этот клип сделал. Сохрани материал, присланный рекламодателем, хотя бы в плохом разрешении, на случай, если придётся отвечать. Ну или наделай ссылок на видео других блогеров с этим шрифтом, как доказательство, что ты тут ни при чём. На худой конец можно спросить лицензии на шрифты.
    Ответ написан
    Комментировать
  • Creative Commons. Как это работает?

    @Mercury13
    Программист на «си с крестами» и не только
    Creative Commons — это лишь стандартные лицензии.

    Использование фото в ролике НЕ будет добросовестным использованием, надо брать фото на стандартных неэксклюзивных условиях или выпрашивать у автора персональную лицензию. Так, в своей программе «Юникодия» я специально просил разрешение на использование двух шрифтов — сирийского и кави. Сирийский не получил — значит, тот, кто будет её распространять коммерчески, должен получить сам. Кави получил — соответственно, пока он в составе «Юникодии», просто бери и не договаривайся.

    Поскольку Армения 80-х была ещё до Creative Commons, единственный способ получить её на условиях Creative Commons — кто-то сфоткал и много десятилетий спустя выложил. Все условия CC, кроме CC0 (аналога отдачи во всеобщее достояние), ТРЕБУЮТ указания автора. Но: можно поискать по государственным архивам, их работы зачастую всеобщее достояние. Не нашим, правда — с этим у нас туго — а американским и немецким.
    Ответ написан
  • Что по смыслу делает этот if?

    @Mercury13
    Программист на «си с крестами» и не только
    Мы тут считываем текстовый файл, и разбор файла по строкам происходит так.
    1. Считываем кусок файла.
    2. Находим \n, если он не в начале буфера.
    3. Движемся назад, пока не увидим начало буфера или другой \n. Отсюль досюль — это строка текстового файла.
    4. Если при компиляции включено FIND_LIB_NAME — пропусти четыре поля, отделённых пробелом, затем кучу пробелов (один или больше), и всё, что до \n — это имя библиотеки. Прямо в буфере заменяем символ конца строки текстового файла на символ конца Си-строки, обрабатываем и возвращаем как было.

    Вообще мне этот исходник не нравится — он сильно завязан на устройство конкретного MAP-файла.
    1. Работа с offset подозрительная — то ли длина каждой строчки является степенью двойки и всё оказывается в порядке, то ли не понимаю что.
    По идее, должны быть два дополнительных блока: 1) если мы упёрлись в конец и хоть один \n считали — всё, что осталось, мы переносим в начало буфера и продолжаем считывание дальше. 2) Если ни одного \n не считали — файл совсем уж странный, слишком длинная строка, выкидываем ошибку.
    2. Если попадёт файл, чей формат совсем другой, система, конечно, не вылезет за пределы буфера, но будет читать непонятно что непонятно откуда. Границами чтения должно быть «отсюль досюль», а не весь буфер. Попытался выяснить, откуда взялся файл — не удивительно, что последний его коммит — это тупая защита от чтения за пределами буфера.
    Ответ написан
    Комментировать
  • Можно ли перекрасить иконку без внутреннего API Qt?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Прямо из исходников applyQIconStyleHelper…
    if (mode != QIcon::Normal) {
        QStyleOption option(0);
        option.palette = QGuiApplication::palette();
        const QPixmap generated = QApplication::style()->generatedIconPixmap(mode, *workingPix, &option);
        if (!generated.isNull()) {
            *workingPix = generated;
        }
    }
    Ответ написан
    Комментировать
  • Возможно ли достичь аргумента с нескольким определением типа?

    @Mercury13
    Программист на «си с крестами» и не только
    Конкретно в вашем случае нет нужды извращаться, перегрузка функций — самое лучшее.

    А так здесь есть два вопроса.
    1. А что напишем в скобках вместо непонятного return?
    2. В какой код оно должно скомпилироваться?

    Пример стандартный шаблонный.
    template <class Device>
    SomeFunction getProcAddress(const Device& device, const std::string& name);
    
    template <>
    inline SomeFunction getProcAddress<VkInstance>(
            const VkInstance& device, const std::string& name)
      { return vkGetInstanceProcAddr(device, name.c_str()); }


    Это стандартное использование шаблонов Си++ с далёкого 1998 года.

    Пример через if constexpr. Си++17, значит.
    template <class Device>
    inline SomeFunction getProcAddress(const Device& device, const std::string& name)
    {
      if constexpr (std::is_same_v<Device, VkInstance>) {
        return vkGetInstanceProcAddr(device, name.c_str());
      } else {
        // false нельзя! — проверка произойдёт в любом случае, будет компилироваться ветка или нет.
        static_assert(std::always_false_v<Device>, "Unknown type");
      }
    }

    Используется в функции std::visit, чтобы исполнить разный код для разных вариантов std::variant и ничего не забыть.

    Что написано в скобках — ну, сами видите. Во что скомпилируется — в две разных функции.

    В некоторых случаях — вероятно, не в вашем — можно ещё поиграться с виртуальным полиморфизмом.
    Ответ написан
  • Кроссплатформенное программирование на C?

    @Mercury13
    Программист на «си с крестами» и не только
    Что тогда делают? Есть три варианта.
    1. Перейти на кроссплатформенную библиотеку (Qt, например).
    2. Наладить свою небольшую библиотеку, которая когда-нибудь станет кроссплатформенной.
    3. Наладить механизм псевдонимов.
    Эти варианты можно объединять: что-то перевести на другую библиотеку, что-то написать своё.

    Примеры из личного кода.

    ОДИН. Ну, например, собственные механизмы работы с путями к файлам потихоньку уходят в сторону std::filesystem::path.

    ДВА. Ну, допустим, сделал свою библиотеку доступа к файлам — бонуса три. 1) Есть функции вроде writeIW (Intel word). 2) Проще писать свои абстрактные потоки, чем с std. 3) Феноменальная скорость под Windows (использует нечастый, но быстрый overlapped API с двойной буферизацией). На остальных ОС — обычная обёртка над FILE*.

    ТРИ. std::random_device из MinGW 9 давал детерминированную последовательность. Потом попытался бросить эту обходную ветку, но кто-то из программистов пожаловался — на его машине r_d просто не инициализировался.
    #if defined(__MINGW32__) && defined(__GNUC__) && !defined(__clang__)
    
        #define MINGW_RANDOM_DEVICE_WORKAROUND
    
        class MingwRandomDevice {};  // куча WinApi, опустим
    #else //defined(__MINGW32__) && defined(__GNUC__) && !defined(__clang__)
        #include <random>
        using MingwRandomDevice = std::random_device;
    #endif //defined(__MINGW32__) && defined(__GNUC__) && !defined(__clang__)
    Ответ написан
    1 комментарий
  • Почему разрешен upcast в RTTI?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Принцип подстановки Лисков — один из важных принципов организации интерфейса объекта. Смысл: само устройство абстракции должно допускать такое, что у нас сын C, но мы безопасно могли работать с отцовскими типами A и B.
    Пример: Отец — прямоугольник с setWidth/setHeight. Сын — квадрат. Значит, уже при проектировании абстракции надо допустить, что setWidth/setHeight или изменит заодно и высоту, или откажется работать, или…
    2. Принцип достаточности. Зачем работать с типом C, если достаточно с B?

    UPD. А для чего этот dynamic_cast вообще? ООП без него проживёт, и часто dynamic_cast — это расписка в плохой конструкции объектов. Но в первую очередь он нужен на API настолько общие, что не совсем понятно, как сделать просто и эффективно. Или требование бинарной совместимости, что важно для всяких там VCL и Qt.
    Ответ написан
    Комментировать
  • Как в Qt сделать DecorationRole, зависящую от DPI экрана?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Опять приходится отвечать самому.

    1. Нашему QListBox’у задаём setIconSize в дипелях.
    2. В data(Qt::DecorationRole) использовать конструктор QIcon(QIconEngine*). Система переводит дипели в пиксели, и работает QIconEngine — объект, содержащий кучу кода и немножко данных, призванный синтезировать иконку нужного размера в аппаратных пикселях.

    Если нужны ещё и разные размеры иконы — патчить QStyledItemDelegate.initStyleOption. Вероятно, тоже в дипелях (не проверял).
    Ответ написан
    Комментировать
  • Выдаст ли ошибку при аллоцировании памяти?

    @Mercury13
    Программист на «си с крестами» и не только
    Нормально.
    Аварии в деструкторе и конструкторе — дела сложные, но возможные.
    Но тут ни того, ни другого не будет. До вызова конструктора просто не дойдёт.
    } catch (const std::bad_alloc&) {}
    Ответ написан
    Комментировать
  • Как сделать элемент поверх другого в QT?

    @Mercury13
    Программист на «си с крестами» и не только
    Самый обычный QWidget
    #wiRound {
      background-color: yellow;
      border-radius: 20;
    }

    6390801eab617817237396.png
    Сам QWidget брошен куда попало, кнопки же расставлены через стандартный vertical layout.
    Ответ написан