Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Clipper. How to cut a polygon using an open polygon?
Started by pahuchiy Jan 24 2019 12:58 AM

13 replies to this topic
clipper
[TOPIC CONTROLS]
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

pahuchiy

[GLOBAL: userInfoPane.html]
pahuchiy
  • Observer

  • 28 posts
  • Corona SDK

line_clipping2.png

The example with ovals uses only closed paths. But how do I get the result like in the picture? Particularly interested in intersection. Do I understand correctly that with open paths I need to use PolyTree? I did not find any such example.



[TOPIC: post.html]
#2

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 842 posts
  • Corona SDK

Hi, pahuchiy.

 

Yes, in reviewing the docs it does sound like a poly-tree is what you want, assuming you need to know the open- or closed-ness of the paths. And I have indeed neglected such an example.  :(

 

Roughly, it might go something like:

local clipper = require("plugin.clipper")

local my_clipper = clipper.NewClipper()
local tree = clipper.NewPolyTree()

-- populate and add to paths to my_clipper

my_clipper:Execute("Intersection", { out = tree })

local open = clipper.OpenPathsFromPolyTree(tree)
local closed = clipper.ClosedPathsFromPolyTree(tree)

I'll try to add such an example, though I can't say how soon. Looks like the docs need a few minor fixes too.


  • pahuchiy likes this

[TOPIC: post.html]
#3

pahuchiy

[GLOBAL: userInfoPane.html]
pahuchiy
  • Observer

  • 28 posts
  • Corona SDK

thanks but not working

local clipper = require("plugin.clipper")
local my_clipper = clipper.NewClipper()
local tree = clipper.NewPolyTree()
print("this text does not appear in the console")
local path1={100,100, 300,100, 300,200, 100, 200}
local path2={140, 70, 220, 320}
local UD1 = clipper.NewPath()
for i = 1, #path1,2 do
  UD1:AddPoint(path1[i], path1[i+1])
end
local subj = clipper.NewPathArray()
subj:AddPath(UD1 )

local UD2 = clipper.NewPath()
for i = 1, #path2,2 do
  UD2:AddPoint(path2[i], path2[i+1])
end
local clip = clipper.NewPathArray()
clip:AddPath(UD2 )
my_clipper:AddPaths(subj, "SubjectClosed")
my_clipper:AddPaths(clip, "Clip")
my_clipper:Execute("Intersection", { out = tree })
local open = clipper.OpenPathsFromPolyTree(tree)
local closed = clipper.ClosedPathsFromPolyTree(tree)


[TOPIC: post.html]
#4

horacebury

[GLOBAL: userInfoPane.html]
horacebury
  • Corona Geek

  • 3,070 posts
  • Corona SDK

I've not seen or used Clipper before (will check it out) but just in case this helps, take a look at my slicer:

 

https://github.com/HoraceBury/slicer

 

There is an interactive build, too.


  • StarCrunch, sporkfin, XeduR @Spyric and 1 other like this

[TOPIC: post.html]
#5

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 842 posts
  • Corona SDK

@pahuchiy If that line of text isn't appearing, the function is probably failing somehow. (Rule #1: the one thing you forget to try will fail publicly  :)) I'll have to take a look.

 

@horacebury Very cool. I only skimmed the source a bit. What sort of process are you following?



[TOPIC: post.html]
#6

horacebury

[GLOBAL: userInfoPane.html]
horacebury
  • Corona Geek

  • 3,070 posts
  • Corona SDK

I'm not. Essentially, it works out the intersections and copies the list of points from the original into two new tables. The hard part is making sure the intersected lines don't generate duplicates.



[TOPIC: post.html]
#7

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 842 posts
  • Corona SDK

I finally had a chance to dig into this yesterday and I believe now have it working. I basically have a rough approximation of the polyline / polygon case at the bottom of this page, cycling between the clip types, and agreeing with the results shown there.

 

There were indeed some issues.  :P

 

I might see about adapting this into another sample too.

 

I should be able to do all the non-Windows builds in the next day or so and then upload all the binaries at once, including the whole gamut for Android.

 

Minor breaking change: in that clip type link, I read some of those rules about open / closed paths a bit clumsily and just assumed only closed clip paths made sense. I've now broken them up into "Clip" and "ClipClosed", following the style used by subject paths. For this reason I'll probably wait until the new uploads go live before updating the samples.



[TOPIC: post.html]
#8

pahuchiy

[GLOBAL: userInfoPane.html]
pahuchiy
  • Observer

  • 28 posts
  • Corona SDK

I finally had a chance to dig into this yesterday and I believe now have it working. I basically have a rough approximation of the polyline / polygon case at the bottom of this page, cycling between the clip types, and agreeing with the results shown there.

 

There were indeed some issues.  :P

 

I might see about adapting this into another sample too.

 

I should be able to do all the non-Windows builds in the next day or so and then upload all the binaries at once, including the whole gamut for Android.

 

Minor breaking change: in that clip type link, I read some of those rules about open / closed paths a bit clumsily and just assumed only closed clip paths made sense. I've now broken them up into "Clip" and "ClipClosed", following the style used by subject paths. For this reason I'll probably wait until the new uploads go live before updating the samples.

 

Please complete the remaining clipper functions. Especially with open paths  :(



[TOPIC: post.html]
#9

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 842 posts
  • Corona SDK

I did update the binaries after my last post. Are you still seeing errors?



[TOPIC: post.html]
#10

pahuchiy

[GLOBAL: userInfoPane.html]
pahuchiy
  • Observer

  • 28 posts
  • Corona SDK

local clipper = require("plugin.clipper")
local my_clipper = clipper.NewClipper()
local tree = clipper.NewPolyTree()
print("this text does not appear in the console")
local path1={100,100, 300,100, 300,200, 100, 200}
local path2={140, 70, 220, 320}
local UD1 = clipper.NewPath()
for i = 1, #path1,2 do
  UD1:AddPoint(path1[i], path1[i+1])
end
local subj = clipper.NewPathArray()
subj:AddPath(UD1 )

local UD2 = clipper.NewPath()
for i = 1, #path2,2 do
  UD2:AddPoint(path2[i], path2[i+1])
end
local clip = clipper.NewPathArray()
clip:AddPath(UD2 )
my_clipper:AddPaths(subj, "SubjectClosed")
my_clipper:AddPaths(clip, "Clip")
my_clipper:Execute("Intersection", { out = tree })
local open = clipper.OpenPathsFromPolyTree(tree)
local closed = clipper.ClosedPathsFromPolyTree(tree)

my code still doesn't work. Please correct my code. I want to get 2 parts of a polygon cut by a line



[TOPIC: post.html]
#11

pixec

[GLOBAL: userInfoPane.html]
pixec
  • Contributor

  • 167 posts
  • Corona SDK

Wow! There is a LUA version of clipper? Thats awesome!


Ive actually been trying to solve polygon union for polygons that are next to each other - you know - two polygons that have one or more common vertexes. But I have not been able to solve how to merge these two polygons. In my scenario there are always two polygons that do not intersect or overlap other than sharing a few common vertexes on their hulls. One polygon is always convex and other is always concave.


. If anyone has any suggestions, I would appreciate.

[TOPIC: post.html]
#12

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 842 posts
  • Corona SDK

@pahuchiy I'll try to give it some attention soon.

 

@pixec If it makes sense, you could try a mesh, which would let you have either separate regions or shared vertices via indexing. I've also bound libtess2 (used in many of the Clipper samples, too), which might let you merge in these cases.


  • pixec likes this

[TOPIC: post.html]
#13

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Corona Geek

  • 1,172 posts
  • Corona SDK

Meshes sound like an interesting approach and that libtess2 by StarCrunch is quite spectacular.

 

@pixec, if you are working with shapes like that, you should be able to get by with simply comparing the edges of the two polygons and determining where they intersect. Then you'd use these intersect points as the merging points for the two polygons. This kind of approach would only work with simple polygons though.


  • horacebury and pixec like this

[TOPIC: post.html]
#14

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 842 posts
  • Corona SDK

@pahuchiy I've gotten a chance to revisit some plugins today.

 

I believe it was just some trouble with the set that was receiving the paths. Here's a revised and expanded version of the above:

local clipper = require("plugin.clipper")
local my_clipper = clipper.NewClipper()
local tree = clipper.NewPolyTree()

print("this text does not appear in the console")

local path1={100,100, 300,100, 300,200, 100, 200}
local path2={140, 70, 220, 320}
local path3={200,150, 400,150, 400,225, 200, 225}

local l1 = display.newLine(unpack(path1))
local l2 = display.newLine(unpack(path2))
local l3 = display.newLine(unpack(path3))

l1.strokeWidth = 3
l2.strokeWidth = 3
l3.strokeWidth = 3
l1:setStrokeColor(1, 0, 0)
l2:setStrokeColor(0, 0, 1)
l3:setStrokeColor(1, 0, 1)

l1:append(100, 100)
l3:append(200, 150)

local UD1 = clipper.NewPath()
for i = 1, #path1,2 do
  UD1:AddPoint(path1[i], path1[i+1])
end

local subj = clipper.NewPathArray()
subj:AddPath(UD1 )

local UD2 = clipper.NewPath()
for i = 1, #path2,2 do
  UD2:AddPoint(path2[i], path2[i+1])
end

local UD3 = clipper.NewPath()
for i = 1, #path3,2 do
  UD3:AddPoint(path3[i], path3[i+1])
end

local clip = clipper.NewPathArray()
clip:AddPath(UD2 )

my_clipper:AddPaths(subj, "ClipClosed")--"SubjectClosed")
my_clipper:AddPaths(clip, "Subject")--"Clip")
my_clipper:AddPath(UD3, "SubjectClosed")
my_clipper:Execute("Intersection", { out = tree })

local open = clipper.OpenPathsFromPolyTree(tree)
local closed = clipper.ClosedPathsFromPolyTree(tree)

print("O",open)
print("C",closed)

for _, set in ipairs{open, closed} do
  for i = 1, #set do
   local out, path = {}, set:GetPath(i)

   for j = 1, #path do
     local x, y = path:GetPoint(j)

     out[#out + 1] = x
     out[#out + 1] = y
   end

   if set == closed then
     local x, y = path:GetPoint(1)

     out[#out + 1] = x
     out[#out + 1] = y
   end

   local l4 = display.newLine(unpack(out))

   l4.strokeWidth = 3
   l4:setStrokeColor(0, 1, 0)
  end
end

  • pixec likes this


[topic_controls]
[/topic_controls]

Also tagged with one or more of these keywords: clipper