Skip to content
Merged

Dev #32

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
name: Build

on: [push, pull_request]
on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:

Expand Down
25 changes: 25 additions & 0 deletions include/shape/elements_intersections.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,31 @@ std::pair<bool, Point> compute_line_intersection(
const Point& p21,
const Point& p22);

/**
* Compute the intersection points of the infinite line through line_point_1
* and line_point_2 with the circle (circle_center, circle_radius).
*
* Returns 0 points when there is no intersection, 1 point when the line is
* tangent to the circle, and 2 points otherwise.
*/
std::vector<Point> compute_line_circle_intersections(
const Point& line_point_1,
const Point& line_point_2,
const Point& circle_center,
LengthDbl circle_radius);

/**
* Compute the intersection points of two circles.
*
* Returns 0 points for no intersection or concentric circles, 1 point for
* an external/internal tangency, and 2 points otherwise.
*/
std::vector<Point> compute_circle_circle_intersections(
const Point& center_1,
LengthDbl radius_1,
const Point& center_2,
LengthDbl radius_2);

struct ShapeElementIntersectionsOutput
{
std::vector<ShapeElement> overlapping_parts;
Expand Down
45 changes: 45 additions & 0 deletions include/shape/no_fit_polygon.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#pragma once

#include "shape/shape.hpp"

namespace shape
{

/**
* Compute the No-Fit Polygon (NFP) of two convex shapes.
*
* The NFP of a fixed shape A and an orbiting shape B is the locus of the
* reference point of B (its origin) as B slides around the boundary of A
* without overlap. Equivalently, it is the Minkowski sum A ⊕ (−B).
*
* A point p lies inside the NFP iff placing B's origin at p causes B and A
* to overlap. A point on the boundary means they just touch.
*
* Both shapes must be convex polygons (only line-segment elements, CCW
* winding). An exception is thrown otherwise.
*
* The returned shape is CCW and free of collinear (aligned) vertices.
*
* Algorithm: rotating-calipers Minkowski sum on convex polygons.
* Complexity: O(m + n) where m, n are the vertex counts of A and B.
*/
Shape no_fit_polygon(
const Shape& fixed_shape,
const Shape& orbiting_shape);

/**
* Compute the No-Fit Polygon (NFP) of two general (possibly non-convex)
* shapes.
*
* The algorithm decomposes each shape into convex parts via
* compute_convex_partition, computes the convex NFP for every pair of parts,
* then returns the union of all those convex NFPs.
*
* The result may consist of several disconnected components or contain holes,
* hence the return type is a vector of ShapeWithHoles.
*/
std::vector<ShapeWithHoles> no_fit_polygon(
const ShapeWithHoles& fixed_shape,
const ShapeWithHoles& orbiting_shape);

}
83 changes: 83 additions & 0 deletions include/shape/simplification.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,89 @@
namespace shape
{

/**
* Output of try_extend_to_intersection.
*/
struct ExtendToIntersectionOutput
{
/** True iff the two extended elements intersect at a valid point. */
bool feasible = false;

/**
* Copy of element_prev with its end moved forward to the intersection
* point. Meaningful only when feasible is true.
*/
ShapeElement new_element_prev;

/**
* Copy of element_next with its start moved backward to the intersection
* point. Meaningful only when feasible is true.
*/
ShapeElement new_element_next;
};

/**
* Given two elements that are not yet connected, try to extend the first one
* beyond its end and the second one before its start along their underlying
* geometries (infinite line for line segments, full circle for circular arcs)
* until the two extended elements meet at a common point.
*
* This is the key primitive for removing a middle element that sits between
* element_prev and element_next: if the operation is feasible the two
* neighbours can be stitched directly at the intersection point.
*
* Returns a struct whose feasible flag is true only when a geometrically
* valid intersection exists, i.e. the candidate point is:
* - at or beyond element_prev.end in element_prev's forward direction, and
* - at or before element_next.start in element_next's forward direction.
*
* Full-circle arcs (ShapeElementOrientation::Full) are not supported; the
* function returns feasible = false if either element is a full circle.
*/
ExtendToIntersectionOutput try_extend_to_intersection(
const ShapeElement& element_prev,
const ShapeElement& element_next);


/**
* Output of try_round_corner.
*/
struct RoundCornerOutput
{
/** True iff a valid rounded corner was found. */
bool feasible = false;

/**
* The replacement elements in path order: trimmed first segment (if
* non-zero length), the circular arc, trimmed second segment (if
* non-zero length). Contains 1 to 3 elements; zero-length segments
* are omitted. Meaningful only when feasible is true.
*/
std::vector<ShapeElement> elements;
};

/**
* Given two consecutive line segments sharing a common endpoint (the corner)
* and a target arc radius, replace the sharp corner with a smooth
* line - arc - line transition.
*
* The arc is tangent to both segments at points T1 (on element_prev) and T2
* (on element_next), located at equal distances from the corner along each
* segment. The arc orientation (CCW/CW) matches the turn direction of the
* path.
*
* Returns feasible = false when:
* - either input element is not a line segment,
* - the two segments are collinear or nearly antiparallel, or
* - the tangent length exceeds the length of either segment (radius too
* large for the available geometry).
*/
RoundCornerOutput try_round_corner(
const ShapeElement& element_prev,
const ShapeElement& element_next,
LengthDbl radius);


struct SimplifyInputShape
{
ShapeWithHoles shape;
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ target_sources(Shape_shape PRIVATE
approximation.cpp
supports.cpp
rasterization.cpp
no_fit_polygon.cpp
writer.cpp)
target_include_directories(Shape_shape PUBLIC
${PROJECT_SOURCE_DIR}/include)
Expand Down
Loading
Loading