Is there any way to get CGAL's polyline simplification to work for inner/shared boundaries?
I've been trying to carry out line simplification on polygons belonging to maps with the help of this CGAL guide, e.g. South Korea.
This is a screenshot of South Korea after line simplification with CGAL.
I carried out the line simplification by adding each polygon to CGAL::Constrained_triangulation_plus_2<CDT> ct
and then running CGAL::Polyline_simplification_2::simplify(ct, Cost(), Stop(0.5));
.
The outer boundaries will get simplified but the inner/shared boundaries (between provinces) will not. Is there any way to get the inner/shared boundaries simplified too?
I've also attempted to simplify
each polygon individually and then combining them back together to form the whole country. The issue, however, is that each polygon would get simplified on its own, and so if Polygon1
gets simplified, there's no guarantee that the shared vertices of the adjacent Polygon2
will relocate to the same coordinates as Polygon1
's vertices, and so intersections occur when you put them back together, as will happen with this South Korea map.
Thank you.
See also questions close to this topic
-
DirectSound API explanation
As a college project we have to develop a Server-Client music streaming application using the DirectSound API. However, due to lack of information, guides or tutorials online, the only source I can gather info about it is the piece of code provided below (which was the only thing provided by the lecturer). Can anyone help me understand the general purpose of these functions and the order they should be implemented in?
Thanks in advance.
IDirectSound8 * directSound = nullptr; IDirectSoundBuffer * primaryBuffer = nullptr; IDirectSoundBuffer8 * secondaryBuffer = nullptr; BYTE * dataBuffer = nullptr; DWORD dataBufferSize; DWORD averageBytesPerSecond; // Search the file for the chunk we want // Returns the size of the chunk and its location in the file HRESULT FindChunk(HANDLE fileHandle, FOURCC fourcc, DWORD & chunkSize, DWORD & chunkDataPosition) { HRESULT hr = S_OK; DWORD chunkType; DWORD chunkDataSize; DWORD riffDataSize = 0; DWORD fileType; DWORD bytesRead = 0; DWORD offset = 0; if (SetFilePointer(fileHandle, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { return HRESULT_FROM_WIN32(GetLastError()); } while (hr == S_OK) { if (ReadFile(fileHandle, &chunkType, sizeof(DWORD), &bytesRead, NULL) == 0) { hr = HRESULT_FROM_WIN32(GetLastError()); } if (ReadFile(fileHandle, &chunkDataSize, sizeof(DWORD), &bytesRead, NULL) == 0) { hr = HRESULT_FROM_WIN32(GetLastError()); } switch (chunkType) { case fourccRIFF: riffDataSize = chunkDataSize; chunkDataSize = 4; if (ReadFile(fileHandle, &fileType, sizeof(DWORD), &bytesRead, NULL) == 0) { hr = HRESULT_FROM_WIN32(GetLastError()); } break; default: if (SetFilePointer(fileHandle, chunkDataSize, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER) { return HRESULT_FROM_WIN32(GetLastError()); } } offset += sizeof(DWORD) * 2; if (chunkType == fourcc) { chunkSize = chunkDataSize; chunkDataPosition = offset; return S_OK; } offset += chunkDataSize; if (bytesRead >= riffDataSize) { return S_FALSE; } } return S_OK; } // Read a chunk of data of the specified size from the file at the specifed location into the supplied buffer HRESULT ReadChunkData(HANDLE fileHandle, void * buffer, DWORD buffersize, DWORD bufferoffset) { HRESULT hr = S_OK; DWORD bytesRead; if (SetFilePointer(fileHandle, bufferoffset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { return HRESULT_FROM_WIN32(GetLastError()); } if (ReadFile(fileHandle, buffer, buffersize, &bytesRead, NULL) == 0) { hr = HRESULT_FROM_WIN32(GetLastError()); } return hr; } bool Initialise() { HRESULT result; DSBUFFERDESC bufferDesc; WAVEFORMATEX waveFormat; // Initialize the direct sound interface pointer for the default sound device. result = DirectSoundCreate8(NULL, &directSound, NULL); if (FAILED(result)) { return false; } // Set the cooperative level to priority so the format of the primary sound buffer can be modified. // We use the handle of the desktop window since we are a console application. If you do write a // graphical application, you should use the HWnd of the graphical application. result = directSound->SetCooperativeLevel(GetDesktopWindow(), DSSCL_PRIORITY); if (FAILED(result)) { return false; } // Setup the primary buffer description. bufferDesc.dwSize = sizeof(DSBUFFERDESC); bufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME; bufferDesc.dwBufferBytes = 0; bufferDesc.dwReserved = 0; bufferDesc.lpwfxFormat = NULL; bufferDesc.guid3DAlgorithm = GUID_NULL; // Get control of the primary sound buffer on the default sound device. result = directSound->CreateSoundBuffer(&bufferDesc, &primaryBuffer, NULL); if (FAILED(result)) { return false; } // Setup the format of the primary sound bufffer. // In this case it is a .WAV file recorded at 44,100 samples per second in 16-bit stereo (cd audio format). // Really, we should set this up from the wave file format loaded from the file. waveFormat.wFormatTag = WAVE_FORMAT_PCM; waveFormat.nSamplesPerSec = 44100; waveFormat.wBitsPerSample = 16; waveFormat.nChannels = 2; waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels; waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; waveFormat.cbSize = 0; // Set the primary buffer to be the wave format specified. result = primaryBuffer->SetFormat(&waveFormat); if (FAILED(result)) { return false; } return true; } void Shutdown() { // Destroy the data buffer if (dataBuffer != nullptr) { delete[] dataBuffer; dataBuffer = nullptr; } // Release the primary sound buffer pointer. if (primaryBuffer != nullptr) { primaryBuffer->Release(); primaryBuffer = nullptr; } // Release the direct sound interface pointer. if (directSound != nullptr) { directSound->Release(); directSound = nullptr; } } // Load the wave file into memory and setup the secondary buffer. bool LoadWaveFile(TCHAR * filename) { WAVEFORMATEXTENSIBLE wfx = { 0 }; WAVEFORMATEX waveFormat; DSBUFFERDESC bufferDesc; HRESULT result; IDirectSoundBuffer * tempBuffer; DWORD chunkSize; DWORD chunkPosition; DWORD filetype; HRESULT hr = S_OK; // Open the wave file HANDLE fileHandle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (fileHandle == INVALID_HANDLE_VALUE) { return false; } if (SetFilePointer(fileHandle, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { return false; } // Make sure we have a RIFF wave file FindChunk(fileHandle, fourccRIFF, chunkSize, chunkPosition); ReadChunkData(fileHandle, &filetype, sizeof(DWORD), chunkPosition); if (filetype != fourccWAVE) { return false; } // Locate the 'fmt ' chunk, and copy its contents into a WAVEFORMATEXTENSIBLE structure. FindChunk(fileHandle, fourccFMT, chunkSize, chunkPosition); ReadChunkData(fileHandle, &wfx, chunkSize, chunkPosition); // Find the audio data chunk FindChunk(fileHandle, fourccDATA, chunkSize, chunkPosition); dataBufferSize = chunkSize; // Read the audio data from the 'data' chunk. This is the data that needs to be copied into // the secondary buffer for playing dataBuffer = new BYTE[dataBufferSize]; ReadChunkData(fileHandle, dataBuffer, dataBufferSize, chunkPosition); CloseHandle(fileHandle); // Set the wave format of the secondary buffer that this wave file will be loaded onto. // The value of wfx.Format.nAvgBytesPerSec will be very useful to you since it gives you // an approximate value for how many bytes it takes to hold one second of audio data. waveFormat.wFormatTag = wfx.Format.wFormatTag; waveFormat.nSamplesPerSec = wfx.Format.nSamplesPerSec; waveFormat.wBitsPerSample = wfx.Format.wBitsPerSample; waveFormat.nChannels = wfx.Format.nChannels; waveFormat.nBlockAlign = wfx.Format.nBlockAlign; waveFormat.nAvgBytesPerSec = wfx.Format.nAvgBytesPerSec; waveFormat.cbSize = 0; // Set the buffer description of the secondary sound buffer that the wave file will be loaded onto. // In this example, we setup a buffer the same size as that of the audio data. For the assignment, // your secondary buffer should only be large enough to hold approximately four seconds of data. bufferDesc.dwSize = sizeof(DSBUFFERDESC); bufferDesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY; bufferDesc.dwBufferBytes = dataBufferSize; bufferDesc.dwReserved = 0; bufferDesc.lpwfxFormat = &waveFormat; bufferDesc.guid3DAlgorithm = GUID_NULL; // Create a temporary sound buffer with the specific buffer settings. result = directSound->CreateSoundBuffer(&bufferDesc, &tempBuffer, NULL); if (FAILED(result)) { return false; } // Test the buffer format against the direct sound 8 interface and create the secondary buffer. result = tempBuffer->QueryInterface(IID_IDirectSoundBuffer8, (void**)&secondaryBuffer); if (FAILED(result)) { return false; } // Release the temporary buffer. tempBuffer->Release(); tempBuffer = nullptr; return true; } void ReleaseSecondaryBuffer() { // Release the secondary sound buffer. if (secondaryBuffer != nullptr) { (secondaryBuffer)->Release(); secondaryBuffer = nullptr; } } bool PlayWaveFile() { HRESULT result; unsigned char * bufferPtr1; unsigned long bufferSize1; unsigned char * bufferPtr2; unsigned long bufferSize2; BYTE * dataBufferPtr = dataBuffer; DWORD soundBytesOutput = 0; bool fillFirstHalf = true; LPDIRECTSOUNDNOTIFY8 directSoundNotify; DSBPOSITIONNOTIFY positionNotify[2]; // Set position of playback at the beginning of the sound buffer. result = secondaryBuffer->SetCurrentPosition(0); if (FAILED(result)) { return false; } // Set volume of the buffer to 100%. result = secondaryBuffer->SetVolume(DSBVOLUME_MAX); if (FAILED(result)) { return false; } // Create an event for notification that playing has stopped. This is only useful // when your audio file fits in the entire secondary buffer (as in this example). // For the assignment, you are going to need notifications when the playback has reached the // first quarter of the buffer or the third quarter of the buffer so that you know when // you should copy more data into the secondary buffer. HANDLE playEventHandles[1]; playEventHandles[0] = CreateEvent(NULL, FALSE, FALSE, NULL); result = secondaryBuffer->QueryInterface(IID_IDirectSoundNotify8, (LPVOID*)&directSoundNotify); if (FAILED(result)) { return false; } // This notification is used to indicate that we have finished playing the buffer of audio. In // the assignment, you will need two different notifications as mentioned above. positionNotify[0].dwOffset = DSBPN_OFFSETSTOP; positionNotify[0].hEventNotify = playEventHandles[0]; directSoundNotify->SetNotificationPositions(1, positionNotify); directSoundNotify->Release(); // Now we can fill our secondary buffer and play it. In the assignment, you will not be able to fill // the buffer all at once since the secondary buffer will not be large enough. Instead, you will need to // loop through the data that you have retrieved from the server, filling different sections of the // secondary buffer as you receive notifications. // Lock the first part of the secondary buffer to write wave data into it. In this case, we lock the entire // buffer, but for the assignment, you will only want to lock the half of the buffer that is not being played. // You will definately want to look up the methods for the IDIRECTSOUNDBUFFER8 interface to see what these // methods do and what the parameters are used for. result = secondaryBuffer->Lock(0, dataBufferSize, (void**)&bufferPtr1, (DWORD*)&bufferSize1, (void**)&bufferPtr2, (DWORD*)&bufferSize2, 0); if (FAILED(result)) { return false; } // Copy the wave data into the buffer. If you need to insert some silence into the buffer, insert values of 0. memcpy(bufferPtr1, dataBuffer, bufferSize1); if (bufferPtr2 != NULL) { memcpy(bufferPtr2, dataBuffer, bufferSize2); } // Unlock the secondary buffer after the data has been written to it. result = secondaryBuffer->Unlock((void*)bufferPtr1, bufferSize1, (void*)bufferPtr2, bufferSize2); if (FAILED(result)) { return false; } // Play the contents of the secondary sound buffer. If you want play to go back to the start of the buffer // again, set the last parameter to DSBPLAY_LOOPING instead of 0. If play is already in progress, then // play will just continue. result = secondaryBuffer->Play(0, 0, 0); if (FAILED(result)) { return false; } // Wait for notifications. In this case, we only have one notification so we could use WaitForSingleObject, // but for the assignment you will need more than one notification, so you will need WaitForMultipleObjects result = WaitForMultipleObjects(1, playEventHandles, FALSE, INFINITE); // In this case, we have been notified that playback has finished so we can just finish. In the assignment, // you should use the appropriate notification to determine which part of the secondary buffer needs to be // filled and handle it accordingly. CloseHandle(playEventHandles[0]); return true; }
-
Conversion of Chain Matrix Order From C++ to Javascript Not behaving the same
I am trying to convert code of C++ to javascript as i found C++ on a site https://www.geeksforgeeks.org/matrix-chain-multiplication-dp-8/ but i need in javascript but it doesn't work the same CPP code which gives output of 18 which is correct
#include <bits/stdc++.h> #include <iostream> using namespace std; // Matrix Ai has dimension p[i-1] x p[i] // for i = 1..n int MatrixChainOrder(int p[], int n) { int m[n][n]; int i, j, k, L, q; /* m[i, j] = Minimum number of scalar multiplications needed to compute the matrix A[i]A[i+1]...A[j] = A[i..j] where dimension of A[i] is p[i-1] x p[i] */ // cost is zero when multiplying // one matrix. for (i = 1; i < n; i++) m[i][i] = 0; // L is chain length. for (L = 2; L < n; L++) { for (i = 1; i < n - L + 1; i++) { j = i + L - 1; m[i][j] = INT_MAX; for (k = i; k <= j - 1; k++) { // q = cost/scalar multiplications q = m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j]; if (q < m[i][j]) m[i][j] = q; } } } return m[1][n - 1]; } // Driver Code int main() { int arr[] = { 1, 2, 3, 4 }; int size = sizeof(arr) / sizeof(arr[0]); cout << "Minimum number of multiplications is " << MatrixChainOrder(arr, size); getchar(); return 0; }
Same code done in Javascript with same input but gives output infinity
export default function ChainMatrixOrder(matrixArray, n) { /* For simplicity of the program, one extra row and one extra column are allocated in m[][]. 0th row and 0th column of m[][] are not used */ let m = Array(n).fill(Array(n).fill(0)); let i, j, k, L, q; /* m[i, j] = Minimum number of scalar multiplications needed to compute the matrix A[i]A[i+1]...A[j] = A[i..j] where dimension of A[i] is p[i-1] x p[i] */ // L is chain length. for (L = 2; L < n; L++) { for (i = 1; i < n - L + 1; i++) { j = i + L - 1; m[i][j] = Number.POSITIVE_INFINITY; for (k = i; k <= j - 1; k++) { // q = cost/scalar multiplications q = m[i][k] + m[k + 1][j] + matrixArray[i - 1] * matrixArray[k] * matrixArray[j]; if (q < m[i][j]) m[i][j] = q; } } } console.log(m); return m[1][n - 1]; }
Can anyone please check if i did something wrong
-
Google Benchmark BaseClass Initialization happens before static variable assignment causes problem
I want to use google benchmark to run my codes, which contains a static global variable. In the benchmark's base class, I need to read this variable to perform some setup. But when the benchmark base class is initialized, that static variable is not initialized yet and cause problems.
The Minimal Reproducing Example below contains three files:
test.h
,test.cc
andbenchmark_main.cc
. Thebenchmark_main.cc
contains a benchmark base classInit
. Its constructor reads thedata
variable. But at this time, thedata
variable is still empty.Question: is there a way to make the
data
variable initialization happens before the baseclass initialization? Any other workaround is also welcome.test.h
#include <array> #include <vector> using namespace std; const vector<int>& func(int);
test.cc
#include "test.h" const array<vector<int>,5> data = { vector<int>({1}), {2,3}, {4,5}, {6,7}, {8} }; const vector<int>& func(int index) { return data[index]; }
benchmark_main.cc
#include <benchmark/benchmark.h> #include <iostream> #include "test.h" class Init: public benchmark::Fixture { protected: public: Init() { std::cout << func(1)[0] << '\n'; } }; BENCHMARK_F(Init, A)(benchmark::State &state) { for (auto _ : state) std::cout << func(1)[0] << '\n'; } BENCHMARK_MAIN();
-
Calculating flatness of an array for each point?
I have an array of doubles and want to calculate flatness of it's values. Index of a value is X, while value itself is Y. I want to know if I were to draw a line between these points how sloped it would be. I'm getting something wrong but not sure what as I keep getting division by 0. For some reason denominator is always 0. Can anyone point me to the problem?
int isFlat( int iBar, double &yValues[], int lookback, double almostPercent, double slopeTolerance, double stdDevTolerance, bool debug = false) { // Get the sums double ySum = 0.; double xSum = 0.; for ( int i = iBar; i < iBar + lookback; i++ ) { ySum += yValues[i]; xSum += iBar + i; } // xMean and yMean double xMean = xSum / lookback; double yMean = ySum / lookback; // numerator and denominator double numerator = 0.0; double denominator = 0.0; for ( int i = iBar; i < iBar + lookback; i++ ) { numerator += ( (iBar + i) - xMean) * ( yValues[i] - yMean ); denominator += MathSqrt( (iBar + i) - xMean ); Print(denominator); } if ( MathAbs(denominator)<1.0E-10 ) { Print("Division by zero imminent."); return false; } double slope = numerator / denominator; // Determine distance of points to the line created. // This is simply y = mx + b // The y intercept (b) probably doesn't matter. double distances[]; ArrayResize(distances, lookback); for ( int i = iBar; i < iBar + lookback; i++ ) { //distances[(iBar - i)] = yValues[i] - slope * (iBar - i); distances[(iBar + i)] = MathAbs(slope * (iBar + i) - yValues[i]) / MathSqrt(1. + MathSqrt(slope)); } double stdev = MathStandardDeviation(distances); double almostMultiplier = 1. + almostPercent; if ( MathAbs(slope) < slopeTolerance && stdev < stdDevTolerance ) { return 1; } else if ( almostPercent > 0 && MathAbs(slope) < slopeTolerance * almostMultiplier && stdev < stdDevTolerance * almostMultiplier ) { return 2; } else { return 0; } }
-
how to insert a number or another character after a number and put it on a new line in python
I need to enter the number after the numbers and then put it on a new line I add another number for each line from variable y.
My all code
f = open("demofile.txt", "r") lines = f.readlines() for i in list(lines): w = i[3:] w = ', '.join(w.split()) #print(w) #time.sleep(1) y = i[2] y=int(y)+1 #print(y) c=np.array([w]) #print(c) c1 = [int(i) for i in c[0].replace(" ", "").split(",")] c1=np.array(c1)*-1 c1=np.array([c1]*3) c2=c1*10 c1=np.transpose(c1) c3=c2+c1 a=str(c3).replace("[",'') a=str(a).replace("]",'') a=str(a).replace("\n ",'\n') print(a)
demofile.txt:
<=1 1 2 3
variable a: -11 -21 -31 -12 -22 -32 -13 -23 -33
here I want to put it on a new line after each number addition
I need
-11 1 -21 1 -31 1 -12 2 -22 2 -32 2 -13 3 -23 3 -33 3
-
How to insert a space before and after a character and put on a new line in Python?
I need to insert a character before x1 and after x1 and put on a new line
my code:
f='p11p21p31' y='x1' k=str(y).join(f[i:i+3] for i in range(0, len(f), 3)) #p=' '.join(k[i:i+3] for i in range(0, len(k), 3)) print(k)
My outout
p11x1p21x1p31
I need:
p11 x1 p21 x1 p31 x1
-
Fixing meshes to make them PWN
I intend to use libigl booleanoperations on my meshes, like this:
igl::copyleft::cgal::mesh_boolean(VA, FA, VB, FB, igl::MESH_BOOLEAN_TYPE_MINUS, V, F);
As noted here:
mesh_boolean assumes the inputs are PWN http://www.cs.columbia.edu/cg/mesh-arrangements/#definitions which includes being oriented so that normals computed using right hand rule point outward
So, I have to make sure my meshes are PWN.
PWN: A (triangle) mesh inducing a piecewise constant generalized winding number field. These meshes may contain self-intersections, non-manifold elements, multiple components, degenerate faces, and even open boundaries (seams), so long as the winding number is still piecewise constant.
How can I make my meshes PWN?
Tried
I tried to fix my meshes by MeshFix. But it does much more than just making the meshes PWN. What other tools are available which I might be missing?
-
How can i cut a leaflet layer to only show certain dimentions
Actually i'm working with Leaflet but when i add a leaftlet.webglheatmap layer it uses the entire screen...
I need to show only the data (colour) inside a geoJson polygon, instead of all the map:
I talked with the webglheatmap developer but he told me to create a new shape with webgl, but that is not an option in this minute
I tried Leaflet.Snogylop too, but it just draw a shape outside my map and with some colours it doesnt do the effect.
Thanks in advice
-
Check if a GeoJSON rectangle touches a road
I need to check if a GeoJSON polygon contains within it any roads (or at least ones stored by the Google Maps or similar API).
Using the Google Maps Reverse Geocoding API I am able to get an approximate address for a latlong point, but I can not tell how far away it is from the nearest road. Ideally, if I had this distance I could determine the answer to my question.
Does the Google Maps API or another similar API support this?
-
crop infinite edges of Additive Weighted voronoi diagram cgal
I am using CGAL Voronoi Diagram Adapter to create AW-Voronoi Diagram. link I want to create bounding boxes for each cell of AW-voronoi diagram. I am able to retrieve the vertices of bounded cells using iterator and halfedges. However, for unbounded cells I am not able to retrieve ubounded edge info except for the source of the unbounded half edge. There was some discussion related to this problem but the solution to that post does not solve my problem. I tried this
for(Unbounded_faces_iterator f = VDA.unbounded_faces_begin(); f != VDA.unbounded_faces_end(); f++) { Ccb_halfedge_circulator ec_start = (f)->ccb(); Ccb_halfedge_circulator ec = ec_start; do { if(!ec->has_source() || !ec->has_target()){ Kernel_Exact::Object_2 o = make_object(ec); Kernel_Exact::Ray_2 r; if(assign(r,o)){ return true; } }while ( ++ec != ec_start ); }
when i try the above code the assign also returns false. Is there any direct way to convert halfedge to a ray in case of Voronoi adapter class or any other way i can receive the edge information that is sufficient to convert it to ray. If i can convert it to a ray then i can find its intersection with the iso_rectangle and crop the unbounded edge. Even a little direction towards the solution would be really helpful.
Thanks, VSav
-
CGAL Mean_curvature_flow_skeletonization contract_until_convergence function produces branches that does not exist in input polygon
I use contract_until_convergence function from CGAL Mean_curvature_flow_skeletonization to produce skeleton from input polygon.
In some cases the skeleton creates branches (see top of the image above, skeleton in red color) that does not exist in input polygon. Is there some parameters to set to prevent this ?
using Skeletonization = CGAL::Mean_curvature_flow_skeletonization<Polyhedron>; Skeletonization mean_curve_skeletonizer(polyhedron); mean_curve_skeletonizer.contract_until_convergence();
-
Straight Skeleton from concave polygon in CGAL
I have an image from which I extract contours and turn these into polygons, using the code below see image below:
import os from scipy import ndimage from skimage import io, measure, img_as_bool, img_as_ubyte, filters import skgeom as sg from skgeom.draw import draw from matplotlib import pyplot as plt #Read in the image: filename = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'traces.png') traces = img_as_ubyte(io.imread(filename)) #Find contours in of the traces: Alpha = traces[:,:,3] bool = img_as_bool(Alpha) filled = ndimage.binary_fill_holes(bool) gaussian = filters.gaussian(filled) countours = measure.find_contours(gaussian, 0.9) #Display the image and plot all contours found as polygons: fig, ax = plt.subplots(figsize=(32,16)) skels = [] for countour in countours: approximated_countour = measure.approximate_polygon(countour, 10) poly = sg.Polygon(approximated_countour) draw(poly) print(poly.is_simple()) #skels.append(sg.skeleton.create_interior_straight_skeleton(poly)) #Causes error! ax.axis('off') ax.set_axis_off() plt.show()
The output in the console:
False False False False False False False False False False False False False False False False False
I'm using a python wrapper for CGAL called scikit-geometry.
CGAL reports all the polygons as being not-simple, however as far as I'm aware they should be simple. They do not intersect themselves anywhere and do not have any duplicate points.
Due to CGAL being convinced the polygons are not-simple the function
create_interior_straight_skeleton
throws an error and halts.The error:
RuntimeError: CGAL ERROR: precondition violation! Expr: aOutContour.is_simple() || !"The input polygon is not simple." File: D:\bld\scikit-geometry_1602638892768\_h_env\Library\include\CGAL/create_straight_skeleton_2.h Line: 133
So, am I mistaken and are the polygons indeed not-simple. If so, how could I still skeletonize? Or Is the fault else where and am I doing something else wrong?
-
How can I convince Sympy to come to the same simplification SAINT does for the 1961 MIT undergrad calculus problem?
The program for James R Slagle's MIT thesis A heuristic program that solves symbolic integration problems in freshman calculus, symbolic automatic integrator (SAINT) is famous(ish) for being the first practical "expert system" symbolic integrator and able to solve all of the problems on the MIT Undergraduate Calculus test (pedantically, a couple were missed, but it could have solved them; detailed here in this excellent YouTube video)
His thesis is freely available here: https://dspace.mit.edu/handle/1721.1/11997
I was excited to try Sympy on this because it looked approachable and was a reasonably difficult simplification I happened to already have an answer to .. however, Sympy doesn't simplify the integral to such a good(subjective?) simplification as the 1961 program (though it does return an equivalent result!)
Question and Speculation
How can I convince Sympy to simplify to the same equation?
Why doesn't it come to the same, seemingly-simpler result?Perhaps it chooses the first possible outcome, or
tan**3
is determined to be worse? if so, why doesn't it simplify SAINT's output?)Perhaps it sets off down a different branch when it finds some matching Fu-routine?
Exam problem 3c
Sympy simplification
from sympy import * x = symbols("x", real=True) # should this be assumed? expr_inner = (x**4) / ((1 - x**2)**Rational(5,2)) expr_integral = integrate((expr_inner), x) print(simplify(expr_integral)) (x**4*asin(x) + 4*x**3*sqrt(1 - x**2)/3 - 2*x**2*asin(x) - x*sqrt(1 - x**2) + asin(x))/(x**4 - 2*x**2 + 1)
Proof of Equality
from sympy import * x = symbols("x", real=True) # should this be assumed? expr_saint = asin(x) + Rational(1,3)*tan(asin(x))**3 - tan(asin(x)) expr_sympy = (x**4*asin(x) + 4*x**3*sqrt(1 - x**2)/3 - 2*x**2*asin(x) - x*sqrt(1 - x**2) + asin(x))/(x**4 - 2*x**2 + 1) expr_saint.equals(expr_sympy) # alternatively simplify(expr_saint - expr_sympy) https://stackoverflow.com/a/37115190/ True
Equations Display
-
Symbolic Algebraic Simplifier
I'm trying to solve this equation for x (or y). Is there some way to do it in Matlab? The "simplify" function (even with "steps",100,"All", true) doesn't do it.
-k+Sqrt[x^2+y^2]+Sqrt[(x-ax)^2+y^2]+Sqrt[(x-bx)^2+(y-by)^2]
-
Remove rows until columns are identical over multiple data frames
I have 4
data frames
namedw, x, y, z
each with 3 columns and identical column names. I now execute an operation that removes rows until the column namedType
is identical over all four data frames.To achieve this I am using a
while
loop with the following code:list_df <- list(z, w, x, y) tmp <- lapply(list_df, `[[`, 'Type') i <- as.integer(as.logical(all(sapply(tmp, function(x) all(x == tmp[[1]]))))) while (i == 0) { z <- z[(z$Type %in% x$Type),] y <- y[(y$Type %in% x$Type),] w <- w[(w$Type %in% x$Type),] z <- z[(z$Type %in% w$Type),] y <- y[(y$Type %in% w$Type),] x <- x[(x$Type %in% w$Type),] z <- z[(z$Type %in% y$Type),] x <- x[(x$Type %in% y$Type),] w <- w[(w$Type %in% y$Type),] x <- x[(x$Type %in% z$Type),] w <- w[(w$Type %in% z$Type),] y <- y[(y$Type %in% z$Type),] list_df <- list(z, w, x, y) tmp <- lapply(list_df, `[[`, 'Type') i <- as.integer(as.logical(all(sapply(tmp, function(x) all(x == tmp[[1]]))))) }
In this code, a list is created for the column
Type
of every data frame. Then the valuei
tests for identicality and produces O if false and 1 if true. Thewhile loop
then performs the deletion of rows not included in every data frame and only stops untili
becomes 1.This code works, but applying it to bigger data can result in a long time for the code to go through. Does anybody have an idea on how to simplify this execution?
For reproducible example:
w <- structure(list(Type = c("26809D", "28503C", "360254", "69298N", "32708V", "680681", "329909", "696978", "32993F", "867609", "51206K", "130747"), X1980 = c(NA, NA, NA, 271835, NA, NA, NA, NA, NA, NA, NA, NA), X1981 = c(NA, NA, NA, 290314, NA, NA, NA, NA, NA, NA, NA, NA)), row.names = c("2", "4", "7", "8", "10", "11", "13", "16", "17", "21", "22", "23"), class = "data.frame") x <- structure(list(Type = c("26809D", "28503C", "360254", "69298N", "32708V", "680681", "329909"), X1980 = c(NA, NA, NA, 1026815, NA, NA, NA), X1981 = c(NA, NA, NA, 826849, NA, NA, NA)), row.names = c("2", "4", "7", "8", "10", "11", "13"), class = "data.frame") y <- structure(list(Type = c("26809D", "28503C", "360254", "69298N", "32708V"), X1980 = c(NA_real_, NA_real_, NA_real_, NA_real_, NA_real_), X1981 = c(NA_real_, NA_real_, NA_real_, NA_real_, NA_real_)), row.names = c("2", "4", "7", "8", "10"), class = "data.frame") z <- structure(list(Type = c("26809D", "28503C", "360254", "69298N", "32708V", "680681", "329909", "696978", "32993F", "867609", "51206K", "130747", "50610H"), X1980 = c(NA, NA, NA, 0.264736101439889, NA, NA, NA, NA, NA, NA, NA, NA, NA), X1981 = c(NA, NA, NA, 0.351108848169376, NA, NA, NA, NA, NA, NA, NA, NA, NA)), row.names = c("2", "4", "7", "8", "10", "11", "13", "16", "17", "21", "22", "23", "24" ), class = "data.frame")