暴露CurveWrap
This commit is contained in:
parent
78b1c316da
commit
063a010609
146
api.cjs.js
146
api.cjs.js
@ -22972,6 +22972,151 @@ function PolylineFilletMinArc(pl, radius = 30) {
|
||||
}
|
||||
}
|
||||
|
||||
/** 点p到线段P1P2 的最短距离的平方,线段不延伸 */
|
||||
function GetSqSegDist(p, p1, p2) {
|
||||
let x = p1.x;
|
||||
let y = p1.y;
|
||||
let dx = p2.x - x;
|
||||
let dy = p2.y - y;
|
||||
if (dx !== 0 || dy !== 0) //不是0长度线
|
||||
{
|
||||
let t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);
|
||||
if (t > 1) {
|
||||
x = p2.x;
|
||||
y = p2.y;
|
||||
}
|
||||
else if (t > 0) {
|
||||
x += dx * t;
|
||||
y += dy * t;
|
||||
}
|
||||
}
|
||||
dx = p.x - x;
|
||||
dy = p.y - y;
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
function CrossVector2(a, b) {
|
||||
return a.x * b.y - a.y * b.x;
|
||||
}
|
||||
//Ramer-Douglas-Peucker algorithm
|
||||
function SimplifyDPStep(points, first, last, sqTolerance, simplified, offset) {
|
||||
let maxSqDist = 0;
|
||||
let index;
|
||||
let fp = points[first];
|
||||
let lp = points[last];
|
||||
for (let i = first + 1; i < last; i++) {
|
||||
let p = points[i];
|
||||
let sqDist = GetSqSegDist(p, fp, lp);
|
||||
if (sqDist > maxSqDist) {
|
||||
index = i;
|
||||
maxSqDist = sqDist;
|
||||
}
|
||||
}
|
||||
if (maxSqDist > sqTolerance) {
|
||||
if (index - first > 1)
|
||||
SimplifyDPStep(points, first, index, sqTolerance, simplified, offset);
|
||||
simplified.push(points[index]);
|
||||
if (last - index > 1)
|
||||
SimplifyDPStep(points, index, last, sqTolerance, simplified, offset);
|
||||
}
|
||||
else {
|
||||
//记录偏移
|
||||
let v = new Vector2(lp.x - fp.x, lp.y - fp.y).normalize();
|
||||
for (let i = first + 1; i < last; i++) {
|
||||
let p = points[i];
|
||||
let offsetDist = -CrossVector2(v, { x: p.x - fp.x, y: p.y - fp.y });
|
||||
offset.positiveOffset = Math.max(offset.positiveOffset, offsetDist);
|
||||
offset.negativeOffset = Math.min(offset.negativeOffset, offsetDist);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ramer-Douglas-Peucker 算法
|
||||
function SimplifyDouglasPeucker(points, sqTolerance) {
|
||||
let last = points.length - 1;
|
||||
let simplified = [points[0]];
|
||||
let offset = { negativeOffset: 0, positiveOffset: 0 };
|
||||
SimplifyDPStep(points, 0, last, sqTolerance, simplified, offset);
|
||||
simplified.push(points[last]);
|
||||
return [simplified, offset];
|
||||
}
|
||||
|
||||
/**
|
||||
* 运用此代码将曲线转换为点,并且精简它.
|
||||
* @class CurveWrap
|
||||
*/
|
||||
class CurveWrap {
|
||||
constructor(Curve, KnifRadius = 3, IsOutside = true) {
|
||||
this.Curve = Curve;
|
||||
this.KnifRadius = KnifRadius;
|
||||
this.IsOutside = IsOutside;
|
||||
this.Used = false;
|
||||
this.Holes = [];
|
||||
this.BoundingBox = Curve.BoundingBox;
|
||||
if (Curve instanceof exports.Polyline) {
|
||||
let pts = Polyline2Points(Curve, IsOutside, 0)[1];
|
||||
let [spts, offset] = SimplifyDouglasPeucker(pts, KnifRadius ** 2 + KnifRadius);
|
||||
if (spts.length !== pts.length) {
|
||||
this.SimplyOffset = offset;
|
||||
this.SimplyPolyline = Path2Polyline(spts);
|
||||
this.Curve = this.SimplyPolyline; //保险起见,也更新它
|
||||
this.Area = this.SimplyPolyline.Area;
|
||||
}
|
||||
else //此处更新多段线
|
||||
this.Curve = Path2Polyline(pts);
|
||||
this.Points = spts;
|
||||
}
|
||||
if (this.Area === undefined)
|
||||
this.Area = this.Curve.Area;
|
||||
}
|
||||
ContainsCurve(curve) {
|
||||
if (this.SimplyPolyline)
|
||||
return this.SimplyPolyline.PtInCurve(curve.Curve.StartPoint);
|
||||
return this.Curve.PtInCurve(curve.Curve.StartPoint);
|
||||
}
|
||||
GetOutsidePoints() {
|
||||
if (this.Curve instanceof exports.Circle) {
|
||||
let pts = Circle2Points(this.Curve, this.KnifRadius, 10, true);
|
||||
return pts;
|
||||
}
|
||||
else {
|
||||
let pl = this.SimplyPolyline || this.Curve;
|
||||
let offset = this.KnifRadius;
|
||||
if (this.SimplyOffset)
|
||||
offset += this.SimplyOffset.positiveOffset;
|
||||
if (offset > 0) {
|
||||
let pts = pl.GetStretchPoints();
|
||||
pts = clipperCpp.lib.offsetToPaths({
|
||||
delta: offset * 10000,
|
||||
offsetInputs: [{ data: PathScale(pts, 10000), joinType: clipperLib.JoinType.Miter, endType: clipperLib.EndType.ClosedPolygon }]
|
||||
})[0];
|
||||
PathScale(pts, 0.0001);
|
||||
return pts;
|
||||
}
|
||||
else
|
||||
return this.Points;
|
||||
}
|
||||
}
|
||||
GetInsidePoints() {
|
||||
if (this.Curve instanceof exports.Circle) {
|
||||
let pts = Circle2Points(this.Curve, this.KnifRadius, 10, false);
|
||||
return pts;
|
||||
}
|
||||
else {
|
||||
let pl = this.SimplyPolyline || this.Curve;
|
||||
let offset = -this.KnifRadius;
|
||||
if (this.SimplyOffset) {
|
||||
offset += this.SimplyOffset.negativeOffset;
|
||||
}
|
||||
if (offset < -0.01) {
|
||||
let pls = pl.GetOffsetCurves(offset);
|
||||
if (pls.length)
|
||||
return pls[0].GetStretchPoints();
|
||||
}
|
||||
else
|
||||
return this.Points;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.BUL_IS_LINE_FUZZ = BUL_IS_LINE_FUZZ;
|
||||
exports.CADFiler = CADFiler;
|
||||
exports.Circle2Points = Circle2Points;
|
||||
@ -22979,6 +23124,7 @@ exports.ComputeBiarc = ComputeBiarc;
|
||||
exports.Contour = Contour;
|
||||
exports.ConverToPolylineAndSplitArc = ConverToPolylineAndSplitArc;
|
||||
exports.CurveContainerCurve = CurveContainerCurve;
|
||||
exports.CurveWrap = CurveWrap;
|
||||
exports.Curves2Points = Curves2Points;
|
||||
exports.FeedingToolPath = FeedingToolPath;
|
||||
exports.IsPtsAllOutOrOnReg = IsPtsAllOutOrOnReg;
|
||||
|
File diff suppressed because one or more lines are too long
147
api.esm.js
147
api.esm.js
@ -22963,5 +22963,150 @@ function PolylineFilletMinArc(pl, radius = 30) {
|
||||
}
|
||||
}
|
||||
|
||||
export { Arc, BUL_IS_LINE_FUZZ, BoolOpeartionType, CADFiler, Circle, Circle2Points, ComputeBiarc, Contour, ConverToPolylineAndSplitArc, CurveContainerCurve, Curves2Points, DuplicateRecordCloning, FeedingToolPath, IsPtsAllOutOrOnReg, IsRect, Line, ParseRegionTextPos, PointsSimplify2PolylineAndParseArc, Polyline, Polyline2Points, PolylineFilletMinArc, Production, Shape, ShapeManager, SmartPointsSimply2Polyline, SmartPolylineSimply2Polyline, SplineConver2Polyline, Status, TEXT_BOX, TempPolyline, UpdateDraw, VData2Curve, VKnifToolPath, fastCurveInCurve2, isTargetCurInOrOnSourceCur };
|
||||
/** 点p到线段P1P2 的最短距离的平方,线段不延伸 */
|
||||
function GetSqSegDist(p, p1, p2) {
|
||||
let x = p1.x;
|
||||
let y = p1.y;
|
||||
let dx = p2.x - x;
|
||||
let dy = p2.y - y;
|
||||
if (dx !== 0 || dy !== 0) //不是0长度线
|
||||
{
|
||||
let t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);
|
||||
if (t > 1) {
|
||||
x = p2.x;
|
||||
y = p2.y;
|
||||
}
|
||||
else if (t > 0) {
|
||||
x += dx * t;
|
||||
y += dy * t;
|
||||
}
|
||||
}
|
||||
dx = p.x - x;
|
||||
dy = p.y - y;
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
function CrossVector2(a, b) {
|
||||
return a.x * b.y - a.y * b.x;
|
||||
}
|
||||
//Ramer-Douglas-Peucker algorithm
|
||||
function SimplifyDPStep(points, first, last, sqTolerance, simplified, offset) {
|
||||
let maxSqDist = 0;
|
||||
let index;
|
||||
let fp = points[first];
|
||||
let lp = points[last];
|
||||
for (let i = first + 1; i < last; i++) {
|
||||
let p = points[i];
|
||||
let sqDist = GetSqSegDist(p, fp, lp);
|
||||
if (sqDist > maxSqDist) {
|
||||
index = i;
|
||||
maxSqDist = sqDist;
|
||||
}
|
||||
}
|
||||
if (maxSqDist > sqTolerance) {
|
||||
if (index - first > 1)
|
||||
SimplifyDPStep(points, first, index, sqTolerance, simplified, offset);
|
||||
simplified.push(points[index]);
|
||||
if (last - index > 1)
|
||||
SimplifyDPStep(points, index, last, sqTolerance, simplified, offset);
|
||||
}
|
||||
else {
|
||||
//记录偏移
|
||||
let v = new Vector2(lp.x - fp.x, lp.y - fp.y).normalize();
|
||||
for (let i = first + 1; i < last; i++) {
|
||||
let p = points[i];
|
||||
let offsetDist = -CrossVector2(v, { x: p.x - fp.x, y: p.y - fp.y });
|
||||
offset.positiveOffset = Math.max(offset.positiveOffset, offsetDist);
|
||||
offset.negativeOffset = Math.min(offset.negativeOffset, offsetDist);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ramer-Douglas-Peucker 算法
|
||||
function SimplifyDouglasPeucker(points, sqTolerance) {
|
||||
let last = points.length - 1;
|
||||
let simplified = [points[0]];
|
||||
let offset = { negativeOffset: 0, positiveOffset: 0 };
|
||||
SimplifyDPStep(points, 0, last, sqTolerance, simplified, offset);
|
||||
simplified.push(points[last]);
|
||||
return [simplified, offset];
|
||||
}
|
||||
|
||||
/**
|
||||
* 运用此代码将曲线转换为点,并且精简它.
|
||||
* @class CurveWrap
|
||||
*/
|
||||
class CurveWrap {
|
||||
constructor(Curve, KnifRadius = 3, IsOutside = true) {
|
||||
this.Curve = Curve;
|
||||
this.KnifRadius = KnifRadius;
|
||||
this.IsOutside = IsOutside;
|
||||
this.Used = false;
|
||||
this.Holes = [];
|
||||
this.BoundingBox = Curve.BoundingBox;
|
||||
if (Curve instanceof Polyline) {
|
||||
let pts = Polyline2Points(Curve, IsOutside, 0)[1];
|
||||
let [spts, offset] = SimplifyDouglasPeucker(pts, KnifRadius ** 2 + KnifRadius);
|
||||
if (spts.length !== pts.length) {
|
||||
this.SimplyOffset = offset;
|
||||
this.SimplyPolyline = Path2Polyline(spts);
|
||||
this.Curve = this.SimplyPolyline; //保险起见,也更新它
|
||||
this.Area = this.SimplyPolyline.Area;
|
||||
}
|
||||
else //此处更新多段线
|
||||
this.Curve = Path2Polyline(pts);
|
||||
this.Points = spts;
|
||||
}
|
||||
if (this.Area === undefined)
|
||||
this.Area = this.Curve.Area;
|
||||
}
|
||||
ContainsCurve(curve) {
|
||||
if (this.SimplyPolyline)
|
||||
return this.SimplyPolyline.PtInCurve(curve.Curve.StartPoint);
|
||||
return this.Curve.PtInCurve(curve.Curve.StartPoint);
|
||||
}
|
||||
GetOutsidePoints() {
|
||||
if (this.Curve instanceof Circle) {
|
||||
let pts = Circle2Points(this.Curve, this.KnifRadius, 10, true);
|
||||
return pts;
|
||||
}
|
||||
else {
|
||||
let pl = this.SimplyPolyline || this.Curve;
|
||||
let offset = this.KnifRadius;
|
||||
if (this.SimplyOffset)
|
||||
offset += this.SimplyOffset.positiveOffset;
|
||||
if (offset > 0) {
|
||||
let pts = pl.GetStretchPoints();
|
||||
pts = clipperCpp.lib.offsetToPaths({
|
||||
delta: offset * 10000,
|
||||
offsetInputs: [{ data: PathScale(pts, 10000), joinType: JoinType.Miter, endType: EndType.ClosedPolygon }]
|
||||
})[0];
|
||||
PathScale(pts, 0.0001);
|
||||
return pts;
|
||||
}
|
||||
else
|
||||
return this.Points;
|
||||
}
|
||||
}
|
||||
GetInsidePoints() {
|
||||
if (this.Curve instanceof Circle) {
|
||||
let pts = Circle2Points(this.Curve, this.KnifRadius, 10, false);
|
||||
return pts;
|
||||
}
|
||||
else {
|
||||
let pl = this.SimplyPolyline || this.Curve;
|
||||
let offset = -this.KnifRadius;
|
||||
if (this.SimplyOffset) {
|
||||
offset += this.SimplyOffset.negativeOffset;
|
||||
}
|
||||
if (offset < -0.01) {
|
||||
let pls = pl.GetOffsetCurves(offset);
|
||||
if (pls.length)
|
||||
return pls[0].GetStretchPoints();
|
||||
}
|
||||
else
|
||||
return this.Points;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { Arc, BUL_IS_LINE_FUZZ, BoolOpeartionType, CADFiler, Circle, Circle2Points, ComputeBiarc, Contour, ConverToPolylineAndSplitArc, CurveContainerCurve, CurveWrap, Curves2Points, DuplicateRecordCloning, FeedingToolPath, IsPtsAllOutOrOnReg, IsRect, Line, ParseRegionTextPos, PointsSimplify2PolylineAndParseArc, Polyline, Polyline2Points, PolylineFilletMinArc, Production, Shape, ShapeManager, SmartPointsSimply2Polyline, SmartPolylineSimply2Polyline, SplineConver2Polyline, Status, TEXT_BOX, TempPolyline, UpdateDraw, VData2Curve, VKnifToolPath, fastCurveInCurve2, isTargetCurInOrOnSourceCur };
|
||||
//# sourceMappingURL=api.esm.js.map
|
||||
|
File diff suppressed because one or more lines are too long
26
types/Nest/Converter/CurveWrap.d.ts
vendored
Normal file
26
types/Nest/Converter/CurveWrap.d.ts
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
import { Box3 } from "three";
|
||||
import { Circle } from "../../DatabaseServices/Entity/Circle";
|
||||
import { Polyline } from "../../DatabaseServices/Entity/Polyline";
|
||||
import { Point } from "../Common/Point";
|
||||
import { IOffset } from "./Simplify2";
|
||||
/**
|
||||
* 运用此代码将曲线转换为点,并且精简它.
|
||||
* @class CurveWrap
|
||||
*/
|
||||
export declare class CurveWrap {
|
||||
Curve: Polyline | Circle;
|
||||
KnifRadius: number;
|
||||
IsOutside: boolean;
|
||||
BoundingBox: Box3;
|
||||
Area: number;
|
||||
SimplyPolyline: Polyline;
|
||||
SimplyOffset: IOffset;
|
||||
Used: boolean;
|
||||
Holes: CurveWrap[];
|
||||
Points: Point[];
|
||||
constructor(Curve: Polyline | Circle, KnifRadius?: number, IsOutside?: boolean);
|
||||
ContainsCurve(curve: CurveWrap): boolean;
|
||||
GetOutsidePoints(): Point[];
|
||||
GetInsidePoints(): Point[];
|
||||
}
|
||||
//# sourceMappingURL=CurveWrap.d.ts.map
|
1
types/Nest/Converter/CurveWrap.d.ts.map
Normal file
1
types/Nest/Converter/CurveWrap.d.ts.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"CurveWrap.d.ts","sourceRoot":"","sources":["../../../../src/Nest/Converter/CurveWrap.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,sCAAsC,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,wCAAwC,CAAC;AAElE,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAIxC,OAAO,EAAE,OAAO,EAA0B,MAAM,aAAa,CAAC;AAG9D;;;GAGG;AACH,qBAAa,SAAS;IAaC,KAAK,EAAE,QAAQ,GAAG,MAAM;IAAS,UAAU;IAAa,SAAS,EAAE,OAAO;IAX7F,WAAW,EAAE,IAAI,CAAC;IAElB,IAAI,EAAE,MAAM,CAAC;IAEb,cAAc,EAAE,QAAQ,CAAC;IACzB,YAAY,EAAE,OAAO,CAAC;IACtB,IAAI,UAAS;IACb,KAAK,EAAE,SAAS,EAAE,CAAM;IAExB,MAAM,EAAE,KAAK,EAAE,CAAC;gBAEG,KAAK,EAAE,QAAQ,GAAG,MAAM,EAAS,UAAU,SAAI,EAAS,SAAS,GAAE,OAAc;IAwBpG,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO;IAOxC,gBAAgB,IAAI,KAAK,EAAE;IA+B3B,eAAe,IAAI,KAAK,EAAE;CA2B7B"}
|
2
types/Nest/Converter/Curves2Points.d.ts
vendored
2
types/Nest/Converter/Curves2Points.d.ts
vendored
@ -9,7 +9,7 @@ export declare function Circle2Points(circle: Circle, knifRadius: number, splitS
|
||||
export declare function Curves2Points(cu: Circle | Polyline, outside: boolean, knifeRadius: number): [(Circle | Polyline), Point[]];
|
||||
export declare function Polyline2Points(pl: Polyline, outside: boolean, knifeRadius: number): [Polyline, Point[]];
|
||||
/**
|
||||
* 移除小圆弧,使用尖角直连
|
||||
* 移除小圆弧,使用尖角直连(有可能产生自交 概率不大)
|
||||
* @param pl 请传入逆时针多段线(我们将直接修改这个多段线,如果你不想被修改 你应该拷贝一个)
|
||||
* @param [radius=30]
|
||||
*/
|
||||
|
11
types/Nest/Converter/Simplify2.d.ts
vendored
Normal file
11
types/Nest/Converter/Simplify2.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
interface P {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
export interface IOffset {
|
||||
negativeOffset: number;
|
||||
positiveOffset: number;
|
||||
}
|
||||
export declare function SimplifyDouglasPeucker(points: P[], sqTolerance: number): [P[], IOffset];
|
||||
export {};
|
||||
//# sourceMappingURL=Simplify2.d.ts.map
|
1
types/Nest/Converter/Simplify2.d.ts.map
Normal file
1
types/Nest/Converter/Simplify2.d.ts.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"Simplify2.d.ts","sourceRoot":"","sources":["../../../../src/Nest/Converter/Simplify2.ts"],"names":[],"mappings":"AAEA,UAAU,CAAC;IAEP,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,OAAO;IAEpB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CAC1B;AA0ED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,OAAO,CAAC,CAQvF"}
|
1
types/api.d.ts
vendored
1
types/api.d.ts
vendored
@ -15,5 +15,6 @@ export * from "./DatabaseServices/Contour";
|
||||
export * from "./DatabaseServices/Shape";
|
||||
export * from "./DatabaseServices/ShapeManager";
|
||||
export * from "./Nest/Converter/Curves2Points";
|
||||
export * from "./Nest/Converter/CurveWrap";
|
||||
export * from "./Common/Status";
|
||||
//# sourceMappingURL=api.d.ts.map
|
@ -1 +1 @@
|
||||
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oCAAoC,CAAC;AACnD,cAAc,0CAA0C,CAAC;AACzD,cAAc,mCAAmC,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAC5E,cAAc,yCAAyC,CAAC;AACxD,cAAc,sBAAsB,CAAC;AACrC,cAAc,wCAAwC,CAAC;AACvD,cAAc,yDAAyD,CAAC;AACxE,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,iCAAiC,CAAC;AAGhD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iBAAiB,CAAC"}
|
||||
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oCAAoC,CAAC;AACnD,cAAc,0CAA0C,CAAC;AACzD,cAAc,mCAAmC,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAC5E,cAAc,yCAAyC,CAAC;AACxD,cAAc,sBAAsB,CAAC;AACrC,cAAc,wCAAwC,CAAC;AACvD,cAAc,yDAAyD,CAAC;AACxE,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,iCAAiC,CAAC;AAGhD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iBAAiB,CAAC"}
|
Loading…
Reference in New Issue
Block a user