Commit e84bd17e authored by Paul Asmuth's avatar Paul Asmuth
Browse files

add the 'marker-shape' option

parent ece669b4
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include "return_code.h"
#include "graphics/measure.h"
#include "scale.h"
#include "sexpr_conv.h"

namespace fviz {

@@ -65,6 +66,12 @@ ReturnCode data_load(
    const Expr* expr,
    std::vector<Measure>* values);

template <typename T>
ReturnCode data_load_as(
    const Expr* expr,
    ExprConvTo<T> conv,
    std::vector<T>* dst);

ReturnCode data_to_measures(
    std::vector<std::string>& src,
    const ScaleConfig& scale,
@@ -72,3 +79,5 @@ ReturnCode data_to_measures(

} // namespace fviz

#include "data_impl.h"

core/data_impl.h

0 → 100644
+41 −0
Original line number Diff line number Diff line
/**
 * This file is part of the "fviz" project
 *   Copyright (c) 2018 Paul Asmuth
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once

namespace fviz {

template <typename T>
ReturnCode data_load_as(
    const Expr* expr,
    ExprConvTo<T> conv,
    std::vector<T>* dst) {
  std::vector<std::string> data;
  if (auto rc = data_load_strings(expr, &data); !rc) {
    return rc;
  }

  for (const auto& d : data) {
    T v;
    if (auto rc = conv(d, &v); !rc) {
      return rc;
    }

    dst->emplace_back(std::move(v));
  }

  return OK;
}

} // namespace fviz
+1 −0
Original line number Diff line number Diff line
@@ -115,6 +115,7 @@ int fviz_configure_file(

int fviz_render_to(fviz_t* ctx, void* backend) {
  auto layer = static_cast<Layer*>(backend);
  layer->font = ctx->env.font;

  LayoutInfo layout;
  layout.content_box = layout_margin_box(
+2 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "text_shaper.h"
#include "measure.h"
#include "layer_ops.h"
#include "font_lookup.h"

namespace fviz {

@@ -45,6 +46,7 @@ struct Layer {
  const double width;
  const double height;
  double dpi;
  FontInfo font;
  Measure font_size;
  const std::shared_ptr<text::TextShaper> text_shaper;
  const std::function<Status (const layer_ops::Op&)> apply;

core/marker.cc

0 → 100644
+163 −0
Original line number Diff line number Diff line
/**
 * This file is part of the "fviz" project
 *   Copyright (c) 2018 Paul Asmuth
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "marker.h"
#include "graphics/path.h"
#include "sexpr_conv.h"

namespace fviz {

const std::unordered_map<std::string, std::string> UNICODE_MARKERS = {
  {"hexagon", "⬢"},
  {"hexagon-o", "⬡"},
};

Marker marker_create_circle(double border_width) {
  border_width = std::clamp(border_width, 0.0, 1.0);

  return [border_width] (const auto& pos, const auto& size, const auto& color, auto target) {
    StrokeStyle style;
    style.color = color;
    style.line_width = from_unit(double(size) * border_width * 0.5);

    Path path;
    path.moveTo(pos.x + size * 0.5, pos.y);
    path.arcTo(pos.x, pos.y, size * 0.5, 0, M_PI * 2);
    strokePath(target, path, style);

    return OK;
  };
}

Marker marker_create_disk() {
  return [] (const auto& pos, const auto& size, const auto& color, auto target) {
    FillStyle style;
    style.color = color;

    Path path;
    path.moveTo(pos.x + size * 0.5, pos.y);
    path.arcTo(pos.x, pos.y, size * 0.5, 0, M_PI * 2);
    fillPath(target, path, style);

    return OK;
  };
}

Marker marker_create_unicode(const std::string& u) {
  return [u] (const auto& pos, const auto& size, const auto& color, auto target) {
    TextStyle style;
    style.font = target->font;
    style.color = color;
    style.font_size = size;

    auto ax = HAlign::CENTER;
    auto ay = VAlign::CENTER;
    if (auto rc = drawTextLabel(u, pos, ax, ay, style, target); rc != OK) {
      return rc;
    }

    return OK;
  };
}

ReturnCode marker_configure(
    const Expr* expr,
    Marker* marker) {

  if (!expr || !expr_is_list(expr)) {
    return errorf(
        ERROR,
        "invalid argument; expected a list (<marker-shape>), but got: {}",
        expr_inspect(expr));
  }

  expr = expr_get_list(expr);

  if (expr_is_value(expr, "disk")) {
    *marker = marker_create_disk();
    return OK;
  }

  if (expr_is_value(expr, "circle")) {
    double border_width = 0.2;
    if (expr_next(expr)) {
      if (auto rc = expr_to_float64(expr_next(expr), &border_width); !rc) {
        return rc;
      }
    }

    *marker = marker_create_circle(border_width);
    return OK;
  }

  if (expr_is_value(expr, "custom")) {
    if (!expr_next(expr) || !expr_is_value(expr_next(expr))) {
      return error(
          ERROR,
          "the 'custom' marker constructor expects exactly one argument");
    }

    *marker = marker_create_unicode(expr_get_value(expr_next(expr)));
    return OK;
  }

  if (expr_is_value(expr)) {
    auto unicode_marker = UNICODE_MARKERS.find(expr_get_value(expr));
    if (unicode_marker != UNICODE_MARKERS.end()) {
      *marker = marker_create_unicode(unicode_marker->second);
      return OK;
    }
  }

  return errorf(
      ERROR,
      "invalid marker shape '{}'; see fviz.org/documentation/marker-shapes for "
      "a list of valid shapes",
      expr_inspect(expr));
}

ReturnCode marker_configure_list(
    const Expr* expr,
    std::vector<Marker>* markers) {
  if (!expr || !expr_is_list(expr)) {
    return errorf(
        ERROR,
        "invalid argument; expected a list (<marker-shape>), but got: {}",
        expr_inspect(expr));
  }

  auto arg0 = expr_get_list(expr);

  if (expr_is_list(arg0)) {
    for (auto arg = arg0; arg; arg = expr_next(arg)) {
      Marker marker;
      if (auto rc = marker_configure(arg, &marker); !rc) {
        return rc;
      }

      markers->emplace_back(std::move(marker));
    }
  } else {
    Marker marker;
    if (auto rc = marker_configure(expr, &marker); !rc) {
      return rc;
    }

    markers->emplace_back(std::move(marker));
  }

  return OK;
}

} // namespace fviz
Loading