| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | #include "geometry.h" |
| | using namespace geoff_geometry; |
| |
|
| | namespace geoff_geometry |
| | { |
| | static Kurve eliminateLoops(const Kurve& k, const Kurve& originalk, double offset, int& ret); |
| | static bool DoesIntersInterfere(const Point& pInt, const Kurve& k, double offset); |
| |
|
| | int Kurve::Offset(vector<Kurve*>& OffsetKurves, double offset, int direction, int method, int& ret) const |
| | { |
| |
|
| | switch (method) { |
| | case NO_ELIMINATION: |
| | case BASIC_OFFSET: { |
| | Kurve* ko = new Kurve; |
| | int n = OffsetMethod1(*ko, offset, direction, method, ret); |
| | OffsetKurves.push_back(ko); |
| | return n; |
| | } |
| |
|
| | default: |
| | FAILURE(L"Requested Offsetting Method not available"); |
| | } |
| | return 0; |
| | } |
| |
|
| | int Kurve::OffsetMethod1(Kurve& kOffset, double off, int direction, int method, int& ret) const |
| | { |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | if (this == &kOffset) { |
| | FAILURE(L"Illegal Call - 'this' must not be kOffset"); |
| | } |
| | double offset = (direction == GEOFF_LEFT) ? off : -off; |
| |
|
| | if (fabs(offset) < geoff_geometry::TOLERANCE || m_nVertices < 2) { |
| | kOffset = *this; |
| | ret = 0; |
| | return 1; |
| | } |
| |
|
| | Span curSpan, curSpanOff; |
| | Span prevSpanOff; |
| | Point p0, p1; |
| |
|
| | |
| | kOffset = Matrix(*this); |
| |
|
| | if (m_mirrored) { |
| | offset = -offset; |
| | } |
| | int RollDir = (off < 0) ? direction : -direction; |
| |
|
| | double scalex; |
| | if (!GetScale(scalex)) { |
| | ret = 1; |
| | return 0; |
| | } |
| | offset /= scalex; |
| |
|
| | bool bClosed = Closed(); |
| | int nspans = nSpans(); |
| | if (bClosed) { |
| | Get(nspans, curSpan, true); |
| |
|
| | prevSpanOff = curSpan.Offset(offset); |
| | nspans++; |
| | } |
| |
|
| | for (int spannumber = 1; spannumber <= nspans; spannumber++) { |
| | if (spannumber > nSpans()) { |
| | Get(1, curSpan, true); |
| | } |
| | else { |
| | Get(spannumber, curSpan, true); |
| | } |
| |
|
| | if (!curSpan.NullSpan) { |
| | int numint = 0; |
| | curSpanOff = curSpan.Offset(offset); |
| | curSpanOff.ID = 0; |
| | if (!kOffset.m_started) { |
| | kOffset.Start(curSpanOff.p0); |
| | kOffset.AddSpanID(0); |
| | } |
| |
|
| | if (spannumber > 1) { |
| | |
| | double d = curSpanOff.p0.Dist(prevSpanOff.p1); |
| | if ((d > geoff_geometry::TOLERANCE) |
| | && (!curSpanOff.NullSpan && !prevSpanOff.NullSpan)) { |
| | |
| |
|
| | double cp = prevSpanOff.ve ^ curSpanOff.vs; |
| | bool inters = (cp > 0 && direction == GEOFF_LEFT) |
| | || (cp < 0 && direction == GEOFF_RIGHT); |
| |
|
| | if (inters) { |
| | double t[4]; |
| | numint = prevSpanOff.Intof(curSpanOff, p0, p1, t); |
| | } |
| |
|
| | if (numint == 1) { |
| | |
| | kOffset.Replace( |
| | kOffset.m_nVertices - 1, |
| | prevSpanOff.dir, |
| | p0, |
| | prevSpanOff.pc, |
| | prevSpanOff.ID |
| | ); |
| | } |
| | else { |
| | |
| | |
| | if (kOffset.Add(RollDir, curSpanOff.p0, curSpan.p0, false)) { |
| | kOffset.AddSpanID(ROLL_AROUND); |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | if (spannumber < m_nVertices) { |
| | curSpanOff.ID = spannumber; |
| | kOffset.Add(curSpanOff, false); |
| | } |
| | else if (numint == 1) { |
| | kOffset.Replace(0, 0, p0, Point(0, 0), 0); |
| | } |
| | } |
| | if (!curSpanOff.NullSpan) { |
| | prevSpanOff = curSpanOff; |
| | } |
| | } |
| |
|
| |
|
| | #ifdef _DEBUG |
| | |
| | |
| | |
| | |
| | |
| | #endif |
| | |
| | if (method == NO_ELIMINATION) { |
| | ret = 0; |
| | return 1; |
| | } |
| | kOffset = eliminateLoops(kOffset, *this, offset, ret); |
| |
|
| | if (ret == 0 && bClosed) { |
| | |
| | if (kOffset.Closed()) { |
| | double a = Area(); |
| | int dir = (a < 0); |
| | double ao = kOffset.Area(); |
| | int dirOffset = ao < 0; |
| |
|
| | if (dir != dirOffset) { |
| | ret = 3; |
| | } |
| | else { |
| | |
| | bool bigger = (a > 0 && offset > 0) || (a < 0 && offset < 0); |
| | if (bigger && fabs(ao) < fabs(a)) { |
| | ret = 2; |
| | } |
| | } |
| | } |
| | else { |
| | ret = 2; |
| | } |
| | } |
| | return (ret == 0) ? 1 : 0; |
| | } |
| |
|
| |
|
| | static Kurve eliminateLoops(const Kurve& k, const Kurve& originalk, double offset, int& ret) |
| | { |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | Span sp0, sp1; |
| | Point pInt, pIntOther; |
| |
|
| | Kurve ko; |
| | ko = Matrix(k); |
| | int kinVertex = 0; |
| |
|
| | while (kinVertex <= k.nSpans()) { |
| | bool clipped = false; |
| |
|
| | sp0.dir = k.Get(kinVertex, sp0.p0, sp0.pc); |
| | sp0.ID = k.GetSpanID(kinVertex++); |
| | if (kinVertex == 1) { |
| | ko.Start(sp0.p0); |
| | ko.AddSpanID(sp0.ID); |
| | } |
| | if (kinVertex <= k.nSpans()) { |
| | int ksaveVertex = kinVertex; |
| | sp0.dir = k.Get(kinVertex, sp0.p1, sp0.pc); |
| | sp0.ID = k.GetSpanID(kinVertex++); |
| |
|
| | sp0.SetProperties(true); |
| |
|
| | int ksaveVertex1 = kinVertex; |
| | if (kinVertex <= k.nSpans()) { |
| | sp1.dir = k.Get(kinVertex, sp1.p0, sp1.pc); |
| | sp1.ID = k.GetSpanID(kinVertex++); |
| | int ksaveVertex2 = kinVertex; |
| |
|
| | int fwdCount = 0; |
| | while (kinVertex <= k.nSpans()) { |
| | sp1.dir = k.Get(kinVertex, sp1.p1, sp1.pc); |
| | sp1.ID = k.GetSpanID(kinVertex++); |
| | sp1.SetProperties(true); |
| |
|
| | double t[4]; |
| | int numint = sp0.Intof(sp1, pInt, pIntOther, t); |
| | if (numint && sp0.p0.Dist(pInt) < geoff_geometry::TOLERANCE) { |
| | numint = 0; |
| | } |
| | if (numint) { |
| |
|
| | if (numint == 2) { |
| | |
| | Span spd = sp0; |
| | spd.p1 = pInt; |
| | spd.SetProperties(true); |
| | double dd = spd.length; |
| |
|
| | spd.p1 = pIntOther; |
| | spd.SetProperties(true); |
| | if (dd > spd.length) { |
| | pInt = pIntOther; |
| | } |
| | numint = 1; |
| | } |
| | ksaveVertex = ksaveVertex1; |
| |
|
| | clipped = true; |
| | if (!DoesIntersInterfere(pInt, originalk, offset)) { |
| | sp0.p1 = pInt; |
| | clipped = false; |
| | break; |
| | } |
| | |
| | } |
| | sp1.p0 = sp1.p1; |
| | ksaveVertex1 = ksaveVertex2; |
| | ksaveVertex2 = kinVertex; |
| |
|
| | if ((kinVertex > k.nSpans() || fwdCount++ > 25) && !clipped) { |
| | break; |
| | } |
| | } |
| | } |
| |
|
| | if (clipped) { |
| | ret = 2; |
| |
|
| | return ko; |
| | } |
| |
|
| | ko.Add(sp0, false); |
| |
|
| | kinVertex = ksaveVertex; |
| | } |
| | } |
| | ret = 0; |
| |
|
| | return ko; |
| | } |
| |
|
| |
|
| | static bool DoesIntersInterfere(const Point& pInt, const Kurve& k, double offset) |
| | { |
| | |
| | Span sp; |
| | Point dummy; |
| | int kCheckVertex = 0; |
| | k.Get(kCheckVertex++, sp.p0, sp.pc); |
| |
|
| | offset = fabs(offset) - geoff_geometry::TOLERANCE; |
| | while (kCheckVertex <= k.nSpans()) { |
| | sp.dir = k.Get(kCheckVertex++, sp.p1, sp.pc); |
| | sp.SetProperties(true); |
| | |
| | if (Dist(sp, pInt, dummy) < offset) { |
| | return true; |
| | } |
| | sp.p0 = sp.p1; |
| | } |
| | return false; |
| | } |
| | } |
| |
|
| |
|
| | static struct iso |
| | { |
| | Span sp; |
| | Span off; |
| | } isodata; |
| | static void isoRadius(Span& before, Span& blend, Span& after, double radius); |
| |
|
| | int Kurve::OffsetISOMethod(Kurve& kOut, double off, int direction, bool BlendAll) const |
| | { |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | double offset = (direction == GEOFF_LEFT) ? off : -off; |
| | if (FEQZ(off) || nSpans() < 1) { |
| | kOut = *this; |
| | return 1; |
| | } |
| | double cptol = 1.0e-05; |
| | std::vector<iso> spans; |
| | for (int i = 0; i < nSpans(); i++) { |
| | Get(i + 1, isodata.sp, true, true); |
| | isodata.off = isodata.sp.Offset(offset); |
| | spans.push_back(isodata); |
| | } |
| |
|
| | for (int i = 0; i < nSpans() - 1; i++) { |
| | if (fabs(spans[i].off.ve ^ spans[i + 1].off.vs) > cptol) { |
| | spans[i].off.JoinSeparateSpans(spans[i + 1].off); |
| | } |
| | } |
| |
|
| | for (int i = 1; i < nSpans() - 1; i++) { |
| | if (spans[i].off.dir) { |
| | if (BlendAll) { |
| | if (spans[i - 1].sp.dir) { |
| | if (spans[i - 1].sp.radius < spans[i].sp.radius) { |
| | continue; |
| | } |
| | } |
| | if (spans[i + 1].sp.dir) { |
| | if (spans[i + 1].sp.radius < spans[i].sp.radius) { |
| | continue; |
| | } |
| | } |
| | } |
| | else { |
| | if ((spans[i - 1].off.dir || spans[i + 1].off.dir)) { |
| | continue; |
| | } |
| | } |
| |
|
| | if ((fabs(spans[i - 1].sp.ve ^ spans[i].sp.vs) < cptol) |
| | && (fabs(spans[i].sp.ve ^ spans[i + 1].sp.vs) < cptol)) { |
| | |
| | isoRadius(spans[i - 1].off, spans[i].off, spans[i + 1].off, spans[i].sp.radius); |
| | } |
| | } |
| | } |
| |
|
| | kOut.Start(spans[0].off.p0); |
| | for (int i = 0; i < nSpans(); i++) { |
| | kOut.Add(spans[i].off.dir, spans[i].off.p1, spans[i].off.pc); |
| | } |
| | return 1; |
| | } |
| |
|
| | static void isoRadius(Span& before, Span& blend, Span& after, double radius) |
| | { |
| | |
| | int direction = ((before.ve ^ after.vs) > 0) ? 1 : -1; |
| | Span beforeOff = before.Offset(direction * radius); |
| | Span afterOff = after.Offset(direction * radius); |
| | int turnLeft = ((before.ve ^ after.vs) > 0) ? 1 : -1; |
| | if (before.dir == LINEAR) { |
| | CLine b(beforeOff); |
| | if (after.dir == LINEAR) { |
| | CLine a(afterOff); |
| | blend.pc = b.Intof(a); |
| | } |
| | else { |
| | Circle a(afterOff); |
| | b.Intof(turnLeft * after.dir, a, blend.pc); |
| | } |
| | } |
| | else { |
| | Circle b(beforeOff); |
| |
|
| | if (after.dir == LINEAR) { |
| | CLine a(afterOff); |
| | a.Intof(-turnLeft * before.dir, b, blend.pc); |
| | } |
| | else { |
| | |
| | Circle a(afterOff); |
| | int leftright = ((Vector2d(b.pc, blend.pc) ^ Vector2d(b.pc, a.pc)) < 0) ? 1 : -1; |
| | b.Intof(leftright, a, blend.pc); |
| | } |
| | } |
| | before.p1 = blend.p0 = before.Near(blend.pc); |
| | after.p0 = blend.p1 = after.Near(blend.pc); |
| | } |
| |
|