|
|
#pragma once
|
|
|
|
|
|
#include "ItemCurve.h"
|
|
|
#include <vector>
|
|
|
#include <utility>
|
|
|
|
|
|
/**
|
|
|
* @brief 样条曲线数据模型
|
|
|
*
|
|
|
* 控制点为唯一数据源,通过段元数据生成渲染点。n 个控制点对应 n-1 段,
|
|
|
* 渲染点带段索引用于绘制和命中检测,最终通过 ToCCurveEx() 输出供文档使用。
|
|
|
*/
|
|
|
|
|
|
/** @brief 段来源:Algorithm 由 Catmull-Rom 计算;Original 使用存储点 */
|
|
|
enum class SegmentSource
|
|
|
{
|
|
|
Algorithm,
|
|
|
Original
|
|
|
};
|
|
|
|
|
|
/** @brief 段元数据,存储该段采样点 */
|
|
|
struct SegmentMeta
|
|
|
{
|
|
|
SegmentSource source = SegmentSource::Algorithm;
|
|
|
std::vector<dfPoint> points;
|
|
|
};
|
|
|
|
|
|
/** @brief 渲染点,带所属段索引,用于绘制和命中检测 */
|
|
|
struct RenderPointWithSeg
|
|
|
{
|
|
|
dfPoint point;
|
|
|
int segIndex;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* @brief 样条曲线模型
|
|
|
*
|
|
|
* 数据流:控制点 → 段元数据 → 渲染点缓存 → CCurveEx
|
|
|
*/
|
|
|
class SplineCurveModel
|
|
|
{
|
|
|
public:
|
|
|
explicit SplineCurveModel(int samplesPerSegment = 30);
|
|
|
|
|
|
const std::vector<dfPoint>& GetControlPoints() const;
|
|
|
std::vector<dfPoint>& GetControlPoints();
|
|
|
const std::vector<SegmentMeta>& GetSegmentMeta() const;
|
|
|
const std::vector<RenderPointWithSeg>& GetRenderPoints() const;
|
|
|
|
|
|
int GetControlPointCount() const;
|
|
|
int GetSegmentCount() const;
|
|
|
bool IsValid() const;
|
|
|
|
|
|
/**
|
|
|
* @brief 在 index 处插入控制点,返回新索引,非法返回 -1
|
|
|
*/
|
|
|
int InsertControlPoint(int index, const dfPoint& point);
|
|
|
|
|
|
/**
|
|
|
* @brief 删除 index 处控制点,至少保留 3 个,返回是否成功
|
|
|
*/
|
|
|
bool RemoveControlPoint(int index);
|
|
|
|
|
|
/** @brief 更新控制点坐标,仅重算受影响的段 */
|
|
|
void UpdateControlPoint(int index, double x, double y);
|
|
|
|
|
|
/**
|
|
|
* @brief 重建渲染点缓存
|
|
|
* @param affectedRange 仅重建此范围,nullptr 表示全量
|
|
|
*/
|
|
|
void RebuildRenderPoints(const std::pair<int, int>* affectedRange = nullptr);
|
|
|
|
|
|
/**
|
|
|
* @brief 从模型生成 CCurveEx,供文档/绘制使用
|
|
|
*/
|
|
|
void ToCCurveEx(CCurveEx& outCurve) const;
|
|
|
|
|
|
/**
|
|
|
* @brief 从 CCurveEx 初始化模型,使用 SplineAlgorithm 抽稀生成控制点
|
|
|
*/
|
|
|
bool InitFromCCurveEx(const CCurveEx& curve, double splineStep);
|
|
|
int GetSamplesPerSegment() const;
|
|
|
void SetSamplesPerSegment(int n);
|
|
|
|
|
|
private:
|
|
|
std::vector<dfPoint> m_controlPoints;
|
|
|
std::vector<SegmentMeta> m_segmentMeta;
|
|
|
std::vector<RenderPointWithSeg> m_renderPoints;
|
|
|
int m_samplesPerSegment;
|
|
|
|
|
|
void InitSegmentMeta();
|
|
|
|
|
|
/**
|
|
|
* Catmull-Rom 单段采样(4 控制点 p0..p3,绘制 p1→p2)
|
|
|
*/
|
|
|
static std::vector<dfPoint> SampleSegment(
|
|
|
const dfPoint& p0, const dfPoint& p1, const dfPoint& p2, const dfPoint& p3,
|
|
|
int samplesPerSegment);
|
|
|
|
|
|
static std::pair<int, int> GetAffectedSegmentRange(int controlPointIndex, int segmentCount);
|
|
|
};
|