2012-08-13 3 views
9

Ich arbeite an einem Projekt mit einem JavaScript-Zeichenbereich und muss den Cursor auf eine bestimmte Entfernung von einem Polygon ausrichten können. Ich kann bereits das Polygon selbst fangen, aber ich muss den Cursor weiter weg haben.Skalieren Sie ein Polygon, sodass die Kanten übereinstimmen

Soweit ich das beurteilen kann, ist es am besten, das Polygon zu skalieren und darauf zu klicken, aber wenn ich das Polygon skaliere, muss der Abstand zwischen den Kanten des alten Polygons und den Kanten des neuen Polygons liegen t immer übereinstimmen.

hier ist ein Beispiel für das Problem:

enter image description here enter image description here

Edit: Die graue das ursprüngliche Polygon darstellt, ist die rote, was ich erhalte, wenn ich das Polygon normal skaliert, und die Grün ist, was ich versuche zu erreichen

Ich habe bereits versucht, das Polygon zum Ursprung zu übersetzen und mit einem Skalierungsfaktor zu multiplizieren, aber kann nicht scheinen, jede Kante um eine bestimmte Entfernung zu skalieren.

+0

Bitte erläutern Sie Ihr Bild, welche Teile tun die rote und die grüne darstellen? – Hogan

+0

Danke. Bearbeitet. – davey555

+0

Können Sie den Code posten, den Sie für das Polygon, die Übersetzung und die Skalierung verwenden? Und was meinst du mit "nicht immer übereinstimmen"? Unter welchen Umständen versagt es? –

Antwort

1

ich eine Lösung JSTS Bibliothek (JavaScript-Port JTS) mit anbieten kann. Die Bibliothek verfügt über Methoden zum Aufblasen/Deflationieren (Versetzen) von Polygonen.

Sie können die Cap- und Join-Stile festlegen, wenn Sie das aufgeblähte Polygon mit verschiedenen Kantenarten erhalten möchten. Das einzige, was Sie tun müssen, ist, dass Sie Polygon konvertieren, um eine JSTS Koordinaten Koordinate, die wirklich einfach:

function inflatePolygon(poly, spacing) { 
    var geoInput = vectorCoordinates2JTS(poly); 
    geoInput.push(geoInput[0]); 

    var geometryFactory = new jsts.geom.GeometryFactory(); 

    var shell = geometryFactory.createPolygon(geoInput); 
    var polygon = shell.buffer(spacing); 
    //try with different cap style 
    //var polygon = shell.buffer(spacing, jsts.operation.buffer.BufferParameters.CAP_FLAT); 

    var inflatedCoordinates = []; 
    var oCoordinates; 
    oCoordinates = polygon.shell.points.coordinates; 

    for (i = 0; i < oCoordinates.length; i++) { 
    var oItem; 
    oItem = oCoordinates[i]; 
    inflatedCoordinates.push(new Vector2(Math.ceil(oItem.x), Math.ceil(oItem.y))); 
    } 
    return inflatedCoordinates; 
} 

:

function vectorCoordinates2JTS (polygon) { var coordinates = []; for (var i = 0; i < polygon.length; i++) { coordinates.push(new jsts.geom.Coordinate(polygon[i].x, polygon[i].y)); } return coordinates; }

Sobald Sie die Koordinaten umgewandelt haben Sie Ihre Polygon aufblasen mit Code, den ich auf jsFiddle gebucht haben, werden Sie etwas wie diese:

enter image description here

Zusätzliche Informationen: Normalerweise verwende ich diese Art von Aufblasen/Ablassen (etwas geändert) zum Festlegen von Grenzen mit Radius auf Polygonen, die auf einer Karte gezeichnet sind (mit Leaflet oder Google Maps). Sie konvertieren nur Lat, Ing-Paare in JSTS-Koordinaten und alles andere ist gleich. Beispiel:

enter image description here

+0

Wow, das ist schön, ich wünschte, ich hätte das vor 3 Jahren ... – davey555

2

Eine Möglichkeit besteht darin, den Abstand zwischen jeder Kante des Polygons und dem Cursorpunkt zu finden und den kleinsten beizubehalten.

Um den Abstand zwischen einem Punkt und einem Liniensegment zu berechnen, projizieren Sie den Punkt auf die Stützlinie. Wenn die Projektion zwischen den Endpunkten liegt, ist die Lösung der Punkt-zu-Linie-Abstand; Andernfalls ist die Lösung die Entfernung zum nächsten Endpunkt.

Dies ist leicht mit Vektorrechnung berechnet.

3

ISTM, was Sie suchen, ist ein Polygon-Versatzalgorithmus oder eine Bibliothek.
Siehe An algorithm for inflating/deflating (offsetting, buffering) polygons

+0

Irgendwelche Ideen, um Polygon-Offset in Javascript zu machen? –

+1

Die Java-Bibliothek JTS (Java Topology Suite) kompensiert (obwohl es dort als Pufferung bezeichnet wird). Siehe https://sourceforge.net/projects/jts-topo-suite/ –

+0

Es ist Java, nicht Javascript und Portierungsprozess wird dort auch benötigt. Wie sieht es mit Clipper aus? –

5

ich jsFiddle gemacht, dass für ein gegebenes Polygon, ein äußeres Polygon berechnet, dass ich hoffe, dass Ihre Anforderung erfüllt. Ich habe die Mathematik dahinter in diesem pdf document gelegt.

Aktualisierung: Code wurde gemacht, um mit vertikalen Linien umzugehen.

function Vector2(x, y) 
{ 
    this.x = x; 
    this.y = y; 
} 

function straight_skeleton(poly, spacing) 
{ 
    // http://stackoverflow.com/a/11970006/796832 
    // Accompanying Fiddle: http://jsfiddle.net/vqKvM/35/ 

    var resulting_path = []; 
    var N = poly.length; 
    var mi, mi1, li, li1, ri, ri1, si, si1, Xi1, Yi1; 
    for(var i = 0; i < N; i++) 
    { 
     mi = (poly[(i+1) % N].y - poly[i].y)/(poly[(i+1) % N].x - poly[i].x); 
     mi1 = (poly[(i+2) % N].y - poly[(i+1) % N].y)/(poly[(i+2) % N].x - poly[(i+1) % N].x); 
     li = Math.sqrt((poly[(i+1) % N].x - poly[i].x)*(poly[(i+1) % N].x - poly[i].x)+(poly[(i+1) % N].y - poly[i].y)*(poly[(i+1) % N].y - poly[i].y)); 
     li1 = Math.sqrt((poly[(i+2) % N].x - poly[(i+1) % N].x)*(poly[(i+2) % N].x - poly[(i+1) % N].x)+(poly[(i+2) % N].y - poly[(i+1) % N].y)*(poly[(i+2) % N].y - poly[(i+1) % N].y)); 
     ri = poly[i].x+spacing*(poly[(i+1) % N].y - poly[i].y)/li; 
     ri1 = poly[(i+1) % N].x+spacing*(poly[(i+2) % N].y - poly[(i+1) % N].y)/li1; 
     si = poly[i].y-spacing*(poly[(i+1) % N].x - poly[i].x)/li; 
     si1 = poly[(i+1) % N].y-spacing*(poly[(i+2) % N].x - poly[(i+1) % N].x)/li1; 
     Xi1 = (mi1*ri1-mi*ri+si-si1)/(mi1-mi); 
     Yi1 = (mi*mi1*(ri1-ri)+mi1*si-mi*si1)/(mi1-mi); 
     // Correction for vertical lines 
     if(poly[(i+1) % N].x - poly[i % N].x==0) 
     { 
      Xi1 = poly[(i+1) % N].x + spacing*(poly[(i+1) % N].y - poly[i % N].y)/Math.abs(poly[(i+1) % N].y - poly[i % N].y); 
      Yi1 = mi1*Xi1 - mi1*ri1 + si1; 
     } 
     if(poly[(i+2) % N].x - poly[(i+1) % N].x==0) 
     { 
      Xi1 = poly[(i+2) % N].x + spacing*(poly[(i+2) % N].y - poly[(i+1) % N].y)/Math.abs(poly[(i+2) % N].y - poly[(i+1) % N].y); 
      Yi1 = mi*Xi1 - mi*ri + si; 
     } 

     //console.log("mi:", mi, "mi1:", mi1, "li:", li, "li1:", li1); 
     //console.log("ri:", ri, "ri1:", ri1, "si:", si, "si1:", si1, "Xi1:", Xi1, "Yi1:", Yi1); 

     resulting_path.push({ 
      x: Xi1, 
      y: Yi1 
     }); 
    } 

    return resulting_path; 
} 


var canvas = document.getElementById("Canvas"); 
var ctx = canvas.getContext("2d"); 

var poly = [ 
    new Vector2(150, 170), 
    new Vector2(400, 120), 
    new Vector2(200, 270), 
    new Vector2(350, 400), 
    new Vector2(210, 470) 
]; 

draw(poly); 
draw(straight_skeleton(poly, 10)); 

function draw(p) { 
    ctx.beginPath(); 
    ctx.moveTo(p[0].x, p[0].y); 
    for(var i = 1; i < p.length; i++) 
    { 
     ctx.lineTo(p[i].x, p[i].y); 
    } 
    ctx.strokeStyle = "#000000"; 
    ctx.closePath(); 
    ctx.stroke(); 
} 

Ein Polygon wird in ein Array von Punktobjekten eingefügt.

Die Funktion draw(p) zeichnet das Polygon auf der Leinwand.

Das angegebene Polygon befindet sich im Array Poly, das Äußere im Array Poly.

spacing ist der Abstand zwischen den Polygonen (wie entlang der Pfeile in Ihrem grünen Diagramm)


Nach Angus Johnson Kommentar, ich habe noch einige Geigen hergestellt, die Probleme zu zeigen, dass er wirft. Dieses Problem ist viel schwieriger als ich zuerst dachte.

+1

Ich hatte einen sehr schnellen Blick auf Ihren Code und ISTM, dass es nur die einfachsten Polygone richtig ausgleichen wird. Zum Beispiel kann ich keinen Code sehen, um sehr spitzwinklige konvexe Winkel zu verwalten, bei denen Scheitelpunkte exponentielle Abstände relativ zum Versatzabstand verschieben können. Auch bei spitzen konkaven Winkeln mit relativ kurzen Seiten muss ein Code vorhanden sein, um die Selbstschnittpunkte zu entfernen, die aus einem einfachen Versatz resultieren. –

+0

@Angus Johnson Ich habe es gerade mit den Bedingungen versucht, die Sie angegeben haben, und ich sehe, was Sie meinen. Danke, dass du darauf hingewiesen hast. Ich werde darüber nachdenken. Vielleicht würde davey555 kommentieren, ob diese Bedingungen in seiner Bewerbung auftreten könnten. – jing3142

6

machte ich eine Javascript-Port von Clipper und mit ihm können Sie die Skalierung in der Art und Weise Sie tun.

Dies ist ein Beispiel für das Aufblasen Polygon:

enter image description here

die LIVE DEMO von Javascript Clipper prüfen.

und holen Sie sich die Datei clipper.js von https://sourceforge.net/projects/jsclipper/.

Full code example wie Polygone zu versetzen und auf html5 Canvas zu zeichnen.

gegenüber der (Abblasen) ist auch möglich, bei Bedarf:

Offsetting polygons

Verwandte Themen